home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 49 / Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso / -serious- / graphics / gnuplot / gnuplot-3.7.1src / gnuplot-3.7.1 / set.c < prev    next >
Text File  |  1999-11-29  |  92KB  |  3,173 lines

  1. #ifndef lint/
  2.  
  3.     ioken++;
  4. Sid = "$Id: set.c,v 1.21.2.1 1999/08/19 14:36:35 lhecking Exp $";
  5. #endif
  6.  
  7. /* GNUPLOT - set.c */
  8.  
  9. /*[
  10.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  11.  *
  12.  * Permission to use, copy, and distribute this software and its
  13.  * documentation for any purpose with or without fee is hereby granted,
  14.  * provided that the above copyright notice appear in all copies and
  15.  * that both that copyright notice and this permission notice appear
  16.  * in supporting documentation.
  17.  *
  18.  * Permission to modify the software is granted, but not the right to
  19.  * distribute the complete modified source code.  Modifications are to
  20.  * be distributed as patches to the released version.  Permission to
  21.  * distribute binaries produced by compiling modified sources is granted,
  22.  * provided you
  23.  *   1. distribute the corresponding source modifications from the
  24.  *    released version in the form of a patch file along with the binaries,
  25.  *   2. add special version identification to distinguish your version
  26.  *    in addition to the base release version number,
  27.  *   3. provide your name and address as the primary contact for the
  28.  *    support of your modified version, and
  29.  *   4. retain our contact information in regard to use of the base
  30.  *    software.
  31.  * Permission to distribute the released version of the source code along
  32.  * with corresponding source modifications in the form of a patch file is
  33.  * granted with same provisions 2 through 4 for binary distributions.
  34.  *
  35.  * This software is provided "as is" without express or implied warranty
  36.  * to the extent permitted by applicable law.
  37. ]*/
  38.  
  39.  
  40. /*
  41.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  42.  * Added user-specified bases for log scaling.
  43.  */
  44.  
  45. #include "plot.h"
  46. #include "stdfn.h"
  47. #include "setshow.h"
  48. #include "national.h"
  49.  
  50. #define DEF_FORMAT   "%g"    /* default format for tic mark labels */
  51. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  52.  
  53. /*
  54.  * global variables to hold status of 'set' options
  55.  *
  56.  * IMPORTANT NOTE:
  57.  * ===============
  58.  * If you change the default values of one of the variables below, or if
  59.  * you add another global variable, make sure that the change you make is
  60.  * done in reset_command() as well (if that makes sense).
  61.  */
  62.  
  63. TBOOLEAN autoscale_r = DTRUE;
  64. TBOOLEAN autoscale_t = DTRUE;
  65. TBOOLEAN autoscale_u = DTRUE;
  66. TBOOLEAN autoscale_v = DTRUE;
  67. TBOOLEAN autoscale_x = DTRUE;
  68. TBOOLEAN autoscale_y = DTRUE;
  69. TBOOLEAN autoscale_z = DTRUE;
  70. TBOOLEAN autoscale_x2 = DTRUE;
  71. TBOOLEAN autoscale_y2 = DTRUE;
  72. TBOOLEAN autoscale_lt = DTRUE;
  73. TBOOLEAN autoscale_lu = DTRUE;
  74. TBOOLEAN autoscale_lv = DTRUE;
  75. TBOOLEAN autoscale_lx = DTRUE;
  76. TBOOLEAN autoscale_ly = DTRUE;
  77. TBOOLEAN autoscale_lz = DTRUE;
  78. TBOOLEAN multiplot = FALSE;
  79.  
  80. double boxwidth = -1.0;        /* box width (automatic) */
  81. TBOOLEAN clip_points = FALSE;
  82. TBOOLEAN clip_lines1 = TRUE;
  83. TBOOLEAN clip_lines2 = FALSE;
  84. struct lp_style_type border_lp = { 0, -2, 0, 1.0, 1.0 };
  85. int draw_border = 31;
  86. TBOOLEAN draw_surface = TRUE;
  87. char dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1] = { "x", "y" };
  88. char default_font[MAX_ID_LEN+1] = "";    /* Entry font added by DJL */
  89. char xformat[MAX_ID_LEN+1] = DEF_FORMAT;
  90. char yformat[MAX_ID_LEN+1] = DEF_FORMAT;
  91. char zformat[MAX_ID_LEN+1] = DEF_FORMAT;
  92. char x2format[MAX_ID_LEN+1] = DEF_FORMAT;
  93. char y2format[MAX_ID_LEN+1] = DEF_FORMAT;
  94.  
  95. /* do formats look like times - use FIRST_X_AXIS etc as index
  96.  * - never saved or shown ...
  97.  */
  98. #if AXIS_ARRAY_SIZE != 10
  99. # error error in initialiser for format_is_numeric
  100. #endif
  101.  
  102. int format_is_numeric[AXIS_ARRAY_SIZE] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
  103.  
  104. enum PLOT_STYLE data_style = POINTSTYLE;
  105. enum PLOT_STYLE func_style = LINES;
  106. double bar_size = 1.0;
  107. struct lp_style_type work_grid = { 0, GRID_OFF, 0, 1.0, 1.0 };
  108. struct lp_style_type grid_lp   = { 0, -1, 0, 1.0, 1.0 };
  109. struct lp_style_type mgrid_lp  = { 0, -1, 0, 1.0, 1.0 };
  110. double polar_grid_angle = 0;    /* nonzero means a polar grid */
  111. int key = -1;            /* default position */
  112. struct position key_user_pos;    /* user specified position for key */
  113. TBOOLEAN key_reverse = FALSE;    /* reverse text & sample ? */
  114. struct lp_style_type key_box = { 0, -3, 0, 1.0, 1.0 };        /* -3 = no linetype */
  115. double key_swidth = 4.0;
  116. double key_vert_factor = 1.0;
  117. double key_width_fix = 0.0;
  118. TBOOLEAN is_log_x = FALSE;
  119. TBOOLEAN is_log_y = FALSE;
  120. TBOOLEAN is_log_z = FALSE;
  121. TBOOLEAN is_log_x2 = FALSE;
  122. TBOOLEAN is_log_y2 = FALSE;
  123. double base_log_x = 0.0;
  124. double base_log_y = 0.0;
  125. double base_log_z = 0.0;
  126. double base_log_x2 = 0.0;
  127. double base_log_y2 = 0.0;
  128. double log_base_log_x = 0.0;
  129. double log_base_log_y = 0.0;
  130. double log_base_log_z = 0.0;
  131. double log_base_log_x2 = 0.0;
  132. double log_base_log_y2 = 0.0;
  133. FILE *gpoutfile;
  134. char *outstr = NULL;        /* means "STDOUT" */
  135. TBOOLEAN parametric = FALSE;
  136. double pointsize = 1.0;
  137. int encoding;
  138. char *encoding_names[] = { "default", "iso_8859_1", "cp437", "cp850", NULL };
  139. TBOOLEAN polar = FALSE;
  140. TBOOLEAN hidden3d = FALSE;
  141. TBOOLEAN label_contours = TRUE;    /* different linestyles are used for contours when set */
  142. char contour_format[32] = "%8.3g";    /* format for contour key entries */
  143. int angles_format = ANGLES_RADIANS;
  144. double ang2rad = 1.0;        /* 1 or pi/180, tracking angles_format */
  145. int mapping3d = MAP3D_CARTESIAN;
  146. int samples = SAMPLES;        /* samples is always equal to samples_1 */
  147. int samples_1 = SAMPLES;
  148. int samples_2 = SAMPLES;
  149. int iso_samples_1 = ISO_SAMPLES;
  150. int iso_samples_2 = ISO_SAMPLES;
  151. float xsize = 1.0;        /* scale factor for size */
  152. float ysize = 1.0;        /* scale factor for size */
  153. float zsize = 1.0;        /* scale factor for size */
  154. float xoffset = 0.0;        /* x origin */
  155. float yoffset = 0.0;        /* y origin */
  156. float aspect_ratio = 0.0;    /* don't attempt to force it */
  157. float surface_rot_z = 30.0;    /* Default 3d transform. */
  158. float surface_rot_x = 60.0;
  159. float surface_scale = 1.0;
  160. float surface_zscale = 1.0;
  161. struct termentry *term = NULL;    /* unknown */
  162. char term_options[MAX_LINE_LEN+1] = "";
  163. label_struct title = { "", 0.0, 0.0, "" };
  164. label_struct timelabel = { "", 0.0, 0.0, "" };
  165. label_struct xlabel = { "", 0.0, 0.0, "" };
  166. label_struct ylabel = { "", 0.0, 0.0, "" };
  167. label_struct zlabel = { "", 0.0, 0.0, "" };
  168. label_struct x2label = { "", 0.0, 0.0, "" };
  169. label_struct y2label = { "", 0.0, 0.0, "" };
  170.  
  171. int timelabel_rotate = FALSE;
  172. int timelabel_bottom = TRUE;
  173. char key_title[MAX_LINE_LEN+1] = "";
  174. double rmin = -0.0;
  175. double rmax = 10.0;
  176. double tmin = -5.0;
  177. double tmax = 5.0;
  178. double umin = -5.0;
  179. double umax = 5.0;
  180. double vmin = -5.0;
  181. double vmax = 5.0;
  182. double xmin = -10.0;
  183. double xmax = 10.0;
  184. double ymin = -10.0;
  185. double ymax = 10.0;
  186. double zmin = -10.0;
  187. double zmax = 10.0;
  188. double x2min = -10.0;
  189. double x2max = 10.0;
  190. double y2min = -10.0;
  191. double y2max = 10.0;
  192. double loff = 0.0;
  193. double roff = 0.0;
  194. double toff = 0.0;
  195. double boff = 0.0;
  196. int draw_contour = CONTOUR_NONE;
  197. int contour_pts = 5;
  198. int contour_kind = CONTOUR_KIND_LINEAR;
  199. int contour_order = 4;
  200. int contour_levels = 5;
  201. double zero = ZERO;        /* zero threshold, not 0! */
  202. int levels_kind = LEVELS_AUTO;
  203. double levels_list[MAX_DISCRETE_LEVELS];    /* storage for z levels to draw contours at */
  204.  
  205. int dgrid3d_row_fineness = 10;
  206. int dgrid3d_col_fineness = 10;
  207. int dgrid3d_norm_value = 1;
  208. TBOOLEAN dgrid3d = FALSE;
  209.  
  210. struct lp_style_type xzeroaxis = { 0, -3, 0, 1.0, 1.0 };
  211. struct lp_style_type yzeroaxis = { 0, -3, 0, 1.0, 1.0 };
  212. struct lp_style_type x2zeroaxis = { 0, -3, 0, 1.0, 1.0 };
  213. struct lp_style_type y2zeroaxis = { 0, -3, 0, 1.0, 1.0 };
  214.  
  215. /* perhaps make these into an array one day */
  216.  
  217. int xtics = TICS_ON_BORDER | TICS_MIRROR;
  218. int ytics = TICS_ON_BORDER | TICS_MIRROR;
  219. int ztics = TICS_ON_BORDER;    /* no mirror by default for ztics */
  220. int x2tics = NO_TICS;
  221. int y2tics = NO_TICS;
  222.  
  223. TBOOLEAN rotate_xtics = FALSE;
  224. TBOOLEAN rotate_ytics = FALSE;
  225. TBOOLEAN rotate_ztics = FALSE;
  226. TBOOLEAN rotate_x2tics = FALSE;
  227. TBOOLEAN rotate_y2tics = FALSE;
  228.  
  229. int range_flags[AXIS_ARRAY_SIZE];    /* = {0,0,...} */
  230.  
  231. int mxtics = MINI_DEFAULT;
  232. int mytics = MINI_DEFAULT;
  233. int mztics = MINI_DEFAULT;
  234. int mx2tics = MINI_DEFAULT;
  235. int my2tics = MINI_DEFAULT;
  236.  
  237. double mxtfreq = 10;        /* # intervals between major */
  238. double mytfreq = 10;        /* tic marks */
  239. double mztfreq = 10;
  240. double mx2tfreq = 10;
  241. double my2tfreq = 10;
  242.  
  243. double ticscale = 1.0;        /* scale factor for tic mark */
  244. double miniticscale = 0.5;    /* and for minitics */
  245.  
  246. float ticslevel = 0.5;
  247.  
  248. struct ticdef xticdef = { TIC_COMPUTED };
  249. struct ticdef yticdef = { TIC_COMPUTED };
  250. struct ticdef zticdef = { TIC_COMPUTED };
  251. struct ticdef x2ticdef = { TIC_COMPUTED };
  252. struct ticdef y2ticdef = { TIC_COMPUTED };
  253.  
  254. TBOOLEAN tic_in = TRUE;
  255.  
  256. struct text_label *first_label = NULL;
  257. struct arrow_def *first_arrow = NULL;
  258. struct linestyle_def *first_linestyle = NULL;
  259.  
  260. int lmargin = -1;        /* space between left edge and xleft in chars (-1: computed) */
  261. int bmargin = -1;        /* space between bottom and ybot in chars (-1: computed) */
  262. int rmargin = -1;        /* space between right egde and xright in chars (-1: computed) */
  263. int tmargin = -1;        /* space between top egde and ytop in chars (-1: computed) */
  264.  
  265. /* string representing missing values in ascii datafiles */
  266. char *missing_val = NULL;
  267.  
  268. /* date&time language conversions */
  269.                  /* extern struct dtconv *dtc; *//* HBB 980317: unused and not defined anywhere !? */
  270.  
  271. /*** other things we need *****/
  272.  
  273. /* input data, parsing variables */
  274.  
  275. extern TBOOLEAN is_3d_plot;
  276.  
  277. /* From plot2d.c */
  278. extern struct curve_points *first_plot;
  279. /* From plot3d.c */
  280. extern struct surface_points *first_3dplot;
  281.  
  282. int key_hpos = TRIGHT;        /* place for curve-labels, corner or outside */
  283. int key_vpos = TTOP;        /* place for curve-labels, corner or below */
  284. int key_just = JRIGHT;        /* alignment of key labels, left or right */
  285.  
  286. #ifndef TIMEFMT
  287. #define TIMEFMT "%d/%m/%y\n%H:%M"
  288. #endif
  289. /* format for date/time for reading time in datafile */
  290. char timefmt[25] = TIMEFMT;
  291.  
  292. /* array of datatypes (x in 0,y in 1,z in 2,..(rtuv)) */
  293. /* not sure how rtuv come into it ?
  294.  * oh well, make first six compatible with FIRST_X_AXIS, etc
  295.  */
  296. int datatype[DATATYPE_ARRAY_SIZE];
  297.  
  298. char cur_locale[MAX_ID_LEN+1] = "C";
  299.  
  300. /* not set or shown directly, but controlled by 'set locale'
  301.  * defined in national.h
  302.  */
  303.  
  304. char full_month_names[12][32] =
  305. { FMON01, FMON02, FMON03, FMON04, FMON05, FMON06, FMON07, FMON08, FMON09, FMON10, FMON11, FMON12 };
  306. char abbrev_month_names[12][8] =
  307. { AMON01, AMON02, AMON03, AMON04, AMON05, AMON06, AMON07, AMON08, AMON09, AMON10, AMON11, AMON12 };
  308.  
  309. char full_day_names[7][32] =
  310. { FDAY0, FDAY1, FDAY2, FDAY3, FDAY4, FDAY5, FDAY6 };
  311. char abbrev_day_names[7][8] =
  312. { ADAY0, ADAY1, ADAY2, ADAY3, ADAY4, ADAY5, ADAY6 };
  313.  
  314.  
  315.  
  316. /******** Local functions ********/
  317. static void get_position __PROTO((struct position * pos));
  318. static void get_position_type __PROTO((enum position_type * type, int *axes));
  319. static void set_xyzlabel __PROTO((label_struct * label));
  320. static void set_label __PROTO((void));
  321. static void set_nolabel __PROTO((void));
  322. static void set_arrow __PROTO((void));
  323. static void set_noarrow __PROTO((void));
  324. static void load_tics __PROTO((int axis, struct ticdef * tdef));
  325. static void load_tic_user __PROTO((int axis, struct ticdef * tdef));
  326. static void free_marklist __PROTO((struct ticmark * list));
  327. static void load_tic_series __PROTO((int axis, struct ticdef * tdef));
  328. static void load_offsets __PROTO((double *a, double *b, double *c, double *d));
  329. static void delete_label __PROTO((struct text_label * prev, struct text_label * this));
  330. static int assign_label_tag __PROTO((void));
  331. static void delete_arrow __PROTO((struct arrow_def * prev, struct arrow_def * this));
  332. static int assign_arrow_tag __PROTO((void));
  333. static void set_linestyle __PROTO((void));
  334. static void set_nolinestyle __PROTO((void));
  335. static int assign_linestyle_tag __PROTO((void));
  336. static void delete_linestyle __PROTO((struct linestyle_def * prev, struct linestyle_def * this));
  337. static TBOOLEAN set_one __PROTO((void));
  338. static TBOOLEAN set_two __PROTO((void));
  339. static TBOOLEAN set_three __PROTO((void));
  340. static int looks_like_numeric __PROTO((char *));
  341. static void set_lp_properties __PROTO((struct lp_style_type * arg, int allow_points, int lt, int pt, double lw, double ps));
  342. static void reset_lp_properties __PROTO((struct lp_style_type *arg));
  343. static void set_locale __PROTO((char *));
  344.  
  345. static int set_tic_prop __PROTO((int *TICS, int *MTICS, double *FREQ,
  346.      struct ticdef * tdef, int AXIS, TBOOLEAN * ROTATE, char *tic_side));
  347.  
  348.  
  349. /* following code segment appears over and over again */
  350. #define GET_NUM_OR_TIME(store,axis) \
  351. do{if ( datatype[axis] == TIME && isstring(c_token) ) { \
  352.     char ss[80]; struct tm tm; \
  353.     quote_str(ss,c_token, 80); ++c_token; \
  354.     if (gstrptime(ss,timefmt,&tm)) store = (double) gtimegm(&tm); else store = 0;\
  355.    } else {\
  356.     struct value value; \
  357.     store = real(const_express(&value));\
  358.   }}while(0)
  359.  
  360. /******** The 'reset' command ********/
  361. void reset_command()
  362. {
  363.     register struct curve_points *f_p = first_plot;
  364.     register struct surface_points *f_3dp = first_3dplot;
  365.  
  366.     c_token++;
  367.     first_plot = NULL;
  368.     first_3dplot = NULL;
  369.     cp_free(f_p);
  370.     sp_free(f_3dp);
  371.     /* delete arrows */
  372.     while (first_arrow != NULL)
  373.     delete_arrow((struct arrow_def *) NULL, first_arrow);
  374.     /* delete labels */
  375.     while (first_label != NULL)
  376.     delete_label((struct text_label *) NULL, first_label);
  377.     /* delete linestyles */
  378.     while (first_linestyle != NULL)
  379.     delete_linestyle((struct linestyle_def *) NULL, first_linestyle);
  380.     strcpy(dummy_var[0], "x");
  381.     strcpy(dummy_var[1], "y");
  382.     strcpy(title.text, "");
  383.     strcpy(xlabel.text, "");
  384.     strcpy(ylabel.text, "");
  385.     strcpy(zlabel.text, "");
  386.     strcpy(x2label.text, "");
  387.     strcpy(y2label.text, "");
  388.     *title.font = 0;
  389.     *xlabel.font = 0;
  390.     *ylabel.font = 0;
  391.     *zlabel.font = 0;
  392.     *x2label.font = 0;
  393.     *y2label.font = 0;
  394.     strcpy(key_title, "");
  395.     strcpy(timefmt, TIMEFMT);
  396.     strcpy(xformat, DEF_FORMAT);
  397.     strcpy(yformat, DEF_FORMAT);
  398.     strcpy(zformat, DEF_FORMAT);
  399.     strcpy(x2format, DEF_FORMAT);
  400.     strcpy(y2format, DEF_FORMAT);
  401.     format_is_numeric[FIRST_X_AXIS] = format_is_numeric[SECOND_X_AXIS] = 1;
  402.     format_is_numeric[FIRST_Y_AXIS] = format_is_numeric[SECOND_Y_AXIS] = 1;
  403.     format_is_numeric[FIRST_Z_AXIS] = format_is_numeric[SECOND_Z_AXIS] = 1;
  404.     autoscale_r = DTRUE;
  405.     autoscale_t = DTRUE;
  406.     autoscale_u = DTRUE;
  407.     autoscale_v = DTRUE;
  408.     autoscale_x = DTRUE;
  409.     autoscale_y = DTRUE;
  410.     autoscale_z = DTRUE;
  411.     autoscale_x2 = DTRUE;
  412.     autoscale_y2 = DTRUE;
  413.     autoscale_lt = DTRUE;
  414.     autoscale_lu = DTRUE;
  415.     autoscale_lv = DTRUE;
  416.     autoscale_lx = DTRUE;
  417.     autoscale_ly = DTRUE;
  418.     autoscale_lz = DTRUE;
  419.     boxwidth = -1.0;
  420.     clip_points = FALSE;
  421.     clip_lines1 = TRUE;
  422.     clip_lines2 = FALSE;
  423.     set_lp_properties(&border_lp, 0, -2, 0, 1.0, 1.0);
  424.     draw_border = 31;
  425.     draw_surface = TRUE;
  426.     data_style = POINTSTYLE;
  427.     func_style = LINES;
  428.     bar_size = 1.0;
  429.     set_lp_properties(&work_grid, 0, GRID_OFF, 0, 0.5, 1.0);
  430.     set_lp_properties(&grid_lp, 0, -1, 0, 0.5, 1.0);
  431.     set_lp_properties(&mgrid_lp, 0, -1, 0, 0.5, 1.0);
  432.     polar_grid_angle = 0;
  433.     key = -1;
  434.     is_log_x = FALSE;
  435.     is_log_y = FALSE;
  436.     is_log_z = FALSE;
  437.     is_log_x2 = FALSE;
  438.     is_log_y2 = FALSE;
  439.     base_log_x = 0.0;
  440.     base_log_y = 0.0;
  441.     base_log_z = 0.0;
  442.     base_log_x2 = 0.0;
  443.     base_log_y2 = 0.0;
  444.     log_base_log_x = 0.0;
  445.     log_base_log_y = 0.0;
  446.     log_base_log_z = 0.0;
  447.     log_base_log_x2 = 0.0;
  448.     log_base_log_y2 = 0.0;
  449.     parametric = FALSE;
  450.     polar = FALSE;
  451.     hidden3d = FALSE;
  452.     label_contours = TRUE;
  453.     strcpy(contour_format, "%8.3g");
  454.     angles_format = ANGLES_RADIANS;
  455.     ang2rad = 1.0;
  456.     mapping3d = MAP3D_CARTESIAN;
  457.     samples = SAMPLES;
  458.     samples_1 = SAMPLES;
  459.     samples_2 = SAMPLES;
  460.     iso_samples_1 = ISO_SAMPLES;
  461.     iso_samples_2 = ISO_SAMPLES;
  462.     xsize = 1.0;
  463.     ysize = 1.0;
  464.     zsize = 1.0;
  465.     xoffset = 0.0;
  466.     yoffset = 0.0;
  467.     aspect_ratio = 0.0;        /* dont force it */
  468.     surface_rot_z = 30.0;
  469.     surface_rot_x = 60.0;
  470.     surface_scale = 1.0;
  471.     surface_zscale = 1.0;
  472.     *timelabel.text = 0;
  473.     timelabel.xoffset = 0;
  474.     timelabel.yoffset = 0;
  475.     *timelabel.font = 0;
  476.     timelabel_rotate = FALSE;
  477.     timelabel_bottom = TRUE;
  478.     title.xoffset = 0;
  479.     title.yoffset = 0;
  480.     xlabel.xoffset = 0;
  481.     xlabel.yoffset = 0;
  482.     ylabel.xoffset = 0;
  483.     ylabel.yoffset = 0;
  484.     zlabel.xoffset = 0;
  485.     zlabel.yoffset = 0;
  486.     x2label.xoffset = 0;
  487.     x2label.yoffset = 0;
  488.     y2label.xoffset = 0;
  489.     y2label.yoffset = 0;
  490.     rmin = -0.0;
  491.     rmax = 10.0;
  492.     tmin = -5.0;
  493.     tmax = 5.0;
  494.     umin = -5.0;
  495.     umax = 5.0;
  496.     vmin = -5.0;
  497.     vmax = 5.0;
  498.     xmin = -10.0;
  499.     xmax = 10.0;
  500.     ymin = -10.0;
  501.     ymax = 10.0;
  502.     zmin = -10.0;
  503.     zmax = 10.0;
  504.     x2min = -10.0;
  505.     x2max = 10.0;
  506.     y2min = -10.0;
  507.     y2max = 10.0;
  508.     memset(range_flags, 0, sizeof(range_flags));    /* all = 0 */
  509.  
  510.     loff = 0.0;
  511.     roff = 0.0;
  512.     toff = 0.0;
  513.     boff = 0.0;
  514.     draw_contour = CONTOUR_NONE;
  515.     contour_pts = 5;
  516.     contour_kind = CONTOUR_KIND_LINEAR;
  517.     contour_order = 4;
  518.     contour_levels = 5;
  519.     zero = ZERO;
  520.     levels_kind = LEVELS_AUTO;
  521.     dgrid3d_row_fineness = 10;
  522.     dgrid3d_col_fineness = 10;
  523.     dgrid3d_norm_value = 1;
  524.     dgrid3d = FALSE;
  525.     set_lp_properties(&xzeroaxis, 0, -3, 0, 1.0, 1.0);
  526.     set_lp_properties(&yzeroaxis, 0, -3, 0, 1.0, 1.0);
  527.     set_lp_properties(&x2zeroaxis, 0, -3, 0, 1.0, 1.0);
  528.     set_lp_properties(&y2zeroaxis, 0, -3, 0, 1.0, 1.0);
  529.     xtics =
  530.     ytics = TICS_ON_BORDER | TICS_MIRROR;
  531.     ztics = TICS_ON_BORDER;    /* no mirror by default */
  532.     x2tics = NO_TICS;
  533.     y2tics = NO_TICS;
  534.     mxtics =
  535.     mytics =
  536.     mztics =
  537.     mx2tics =
  538.     my2tics = MINI_DEFAULT;
  539.     mxtfreq = 10.0;
  540.     mytfreq = 10.0;
  541.     mztfreq = 10.0;
  542.     mx2tfreq = 10.0;
  543.     my2tfreq = 10.0;
  544.     ticscale = 1.0;
  545.     miniticscale = 0.5;
  546.     ticslevel = 0.5;
  547.     xticdef.type = TIC_COMPUTED;
  548.     yticdef.type = TIC_COMPUTED;
  549.     zticdef.type = TIC_COMPUTED;
  550.     x2ticdef.type = TIC_COMPUTED;
  551.     y2ticdef.type = TIC_COMPUTED;
  552.     tic_in = TRUE;
  553.     lmargin =
  554.     bmargin =
  555.     rmargin =
  556.     tmargin = -1;        /* autocomputed */
  557.     key_hpos = TRIGHT;
  558.     key_vpos = TTOP;
  559.     key_just = JRIGHT;
  560.     key_reverse = FALSE;
  561.     set_lp_properties(&key_box, 0, -3, 0, 1.0, 1.0);
  562.     key_swidth = 4;
  563.     key_vert_factor = 1;
  564.     key_width_fix = 0;
  565.     datatype[FIRST_X_AXIS] = FALSE;
  566.     datatype[FIRST_Y_AXIS] = FALSE;
  567.     datatype[FIRST_Z_AXIS] = FALSE;
  568.     datatype[SECOND_X_AXIS] = FALSE;
  569.     datatype[SECOND_Y_AXIS] = FALSE;
  570.     datatype[SECOND_Z_AXIS] = FALSE;
  571.     datatype[R_AXIS] = FALSE;
  572.     datatype[T_AXIS] = FALSE;
  573.     datatype[U_AXIS] = FALSE;
  574.     datatype[V_AXIS] = FALSE;
  575.  
  576.     pointsize = 1.0;
  577.     encoding = ENCODING_DEFAULT;
  578.  
  579.     set_locale("C");        /* default */
  580. }
  581.  
  582. /******** The 'set' command ********/
  583. void set_command()
  584. {
  585.     static char GPFAR setmess[] = "\
  586. valid set options:  [] = choose one, {} means optional\n\n\
  587. \t'angles',  '{no}arrow',  '{no}autoscale',  'bars',  '{no}border',\n\
  588. \t'boxwidth', '{no}clabel', '{no}clip', 'cntrparam', '{no}contour',\n\
  589. \t'data style',  '{no}dgrid3d',  'dummy',  'encoding',  'format',\n\
  590. \t'function style',   '{no}grid',   '{no}hidden3d',   'isosamples',\n\
  591. \t'{no}key', '{no}label', '{no}linestyle', 'locale', '{no}logscale',\n\
  592. \t'[blrt]margin', 'mapping', 'missing', '{no}multiplot', 'offsets',\n\
  593. \t'origin', 'output', '{no}parametric', 'pointsize', '{no}polar',\n\
  594. \t'[rtuv]range',  'samples',  'size',  '{no}surface',  'terminal',\n\
  595. \t'tics',  'ticscale',  'ticslevel',  '{no}timestamp',  'timefmt',\n\
  596. \t'title', 'view', '[xyz]{2}data', '[xyz]{2}label', '[xyz]{2}range',\n\
  597. \t'{no}{m}[xyz]{2}tics', '[xyz]{2}[md]tics', '{no}{[xyz]{2}}zeroaxis',\n\
  598. \t'zero'";
  599.  
  600.     c_token++;
  601.  
  602.     if (!set_one() && !set_two() && !set_three())
  603.     int_error(setmess, c_token);
  604. }
  605.  
  606. /* return TRUE if a command match, FALSE if not */
  607. static TBOOLEAN
  608. set_one()
  609. {
  610. /* save on replication with a macro */
  611. #define PROCESS_AUTO_LETTER(AUTO, STRING,MIN,MAX) \
  612. else if (equals(c_token, STRING))       { AUTO = DTRUE; ++c_token; } \
  613. else if (almost_equals(c_token, MIN)) { AUTO |= 1;    ++c_token; } \
  614. else if (almost_equals(c_token, MAX)) { AUTO |= 2;    ++c_token; }
  615.  
  616.     if (almost_equals(c_token, "ar$row")) {
  617.     c_token++;
  618.     set_arrow();
  619.     } else if (almost_equals(c_token, "noar$row")) {
  620.     c_token++;
  621.     set_noarrow();
  622.     } else if (almost_equals(c_token, "au$toscale")) {
  623.     c_token++;
  624.     if (END_OF_COMMAND) {
  625.         autoscale_r = autoscale_t = autoscale_x = autoscale_y = autoscale_z = autoscale_x2 = autoscale_y2 = DTRUE;
  626.     } else if (equals(c_token, "xy") || equals(c_token, "yx")) {
  627.         autoscale_x = autoscale_y = DTRUE;
  628.         c_token++;
  629.     }
  630.     PROCESS_AUTO_LETTER(autoscale_r, "r", "rmi$n", "rma$x")
  631.     PROCESS_AUTO_LETTER(autoscale_t, "t", "tmi$n", "tma$x")
  632.     PROCESS_AUTO_LETTER(autoscale_u, "u", "umi$n", "uma$x")
  633.     PROCESS_AUTO_LETTER(autoscale_v, "v", "vmi$n", "vma$x")
  634.     PROCESS_AUTO_LETTER(autoscale_x, "x", "xmi$n", "xma$x")
  635.     PROCESS_AUTO_LETTER(autoscale_y, "y", "ymi$n", "yma$x")
  636.     PROCESS_AUTO_LETTER(autoscale_z, "z", "zmi$n", "zma$x")
  637.     PROCESS_AUTO_LETTER(autoscale_x2, "x2", "x2mi$n", "x2ma$x")
  638.     PROCESS_AUTO_LETTER(autoscale_y2, "y2", "y2mi$n", "y2ma$x")
  639.     else
  640.         int_error("Invalid range", c_token);
  641.     } else if (almost_equals(c_token,"noau$toscale")) {
  642.     c_token++;
  643.     if (END_OF_COMMAND) {
  644.         autoscale_r = autoscale_t = autoscale_x = autoscale_y = autoscale_z = FALSE;
  645.     } else if (equals(c_token, "xy") || equals(c_token, "tyx")) {
  646.         autoscale_x = autoscale_y = FALSE;
  647.         c_token++;
  648.     } else if (equals(c_token, "r")) {
  649.         autoscale_r = FALSE;
  650.         c_token++;
  651.     } else if (equals(c_token, "t")) {
  652.         autoscale_t = FALSE;
  653.         c_token++;
  654.     } else if (equals(c_token, "u")) {
  655.         autoscale_u = FALSE;
  656.         c_token++;
  657.     } else if (equals(c_token, "v")) {
  658.         autoscale_v = FALSE;
  659.         c_token++;
  660.     } else if (equals(c_token, "x")) {
  661.         autoscale_x = FALSE;
  662.         c_token++;
  663.     } else if (equals(c_token, "y")) {
  664.         autoscale_y = FALSE;
  665.         c_token++;
  666.     } else if (equals(c_token, "x2")) {
  667.         autoscale_x2 = FALSE;
  668.         c_token++;
  669.     } else if (equals(c_token, "y2")) {
  670.           autoscale_y2 = FALSE;
  671.           c_token++;
  672.     } else if (equals(c_token, "z")) {
  673.         autoscale_z = FALSE;
  674.         c_token++;
  675.     }
  676.     } else if (almost_equals(c_token,"nobor$der")) {
  677.     draw_border = 0;
  678.     c_token++;
  679.     }
  680.     else if (almost_equals(c_token,"box$width")) {
  681.     struct value a;
  682.     c_token++;
  683.     if (END_OF_COMMAND)
  684.         boxwidth = -1.0;
  685.     else
  686. /*              if((boxwidth = real(const_express(&a))) != -2.0)*/
  687. /*                      boxwidth = magnitude(const_express(&a));*/
  688.         boxwidth = real(const_express(&a));
  689.     } else if (almost_equals(c_token,"c$lip")) {
  690.     c_token++;
  691.     if (END_OF_COMMAND)
  692.         /* assuming same as points */
  693.         clip_points = TRUE;
  694.     else if (almost_equals(c_token, "p$oints"))
  695.         clip_points = TRUE;
  696.     else if (almost_equals(c_token, "o$ne"))
  697.         clip_lines1 = TRUE;
  698.     else if (almost_equals(c_token, "t$wo"))
  699.         clip_lines2 = TRUE;
  700.     else
  701.         int_error("expecting 'points', 'one', or 'two'", c_token);
  702.     c_token++;
  703.     } else if (almost_equals(c_token,"noc$lip")) {
  704.     c_token++;
  705.     if (END_OF_COMMAND) {
  706.         /* same as all three */
  707.         clip_points = FALSE;
  708.         clip_lines1 = FALSE;
  709.         clip_lines2 = FALSE;
  710.     } else if (almost_equals(c_token, "p$oints"))
  711.         clip_points = FALSE;
  712.     else if (almost_equals(c_token, "o$ne"))
  713.         clip_lines1 = FALSE;
  714.     else if (almost_equals(c_token, "t$wo"))
  715.         clip_lines2 = FALSE;
  716.     else
  717.         int_error("expecting 'points', 'one', or 'two'", c_token);
  718.     c_token++;
  719.     } else if (almost_equals(c_token,"hi$dden3d")) {
  720. #ifdef LITE
  721.     printf(" Hidden Line Removal Not Supported in LITE version\n");
  722.     c_token++;
  723. #else
  724.     /* HBB 970618: new parsing engine for hidden3d options */
  725.     set_hidden3doptions();
  726.     hidden3d = TRUE;
  727. #endif /* LITE */
  728.     } else if (almost_equals(c_token,"nohi$dden3d")) {
  729. #ifdef LITE
  730.     printf(" Hidden Line Removal Not Supported in LITE version\n");
  731. #else
  732.     hidden3d = FALSE;
  733. #endif /* LITE */
  734.     c_token++;
  735.     } else if (almost_equals(c_token,"cla$bel")) {
  736.     label_contours = TRUE;
  737.     c_token++;
  738.     if (isstring(c_token))
  739.         quote_str(contour_format, c_token++, 30);
  740.     } else if (almost_equals(c_token,"nocla$bel")) {
  741.     label_contours = FALSE;
  742.     c_token++;
  743.     } else if (almost_equals(c_token,"ma$pping3d")) {
  744.     c_token++;
  745.     if (END_OF_COMMAND)
  746.         /* assuming same as points */
  747.         mapping3d = MAP3D_CARTESIAN;
  748.     else if (almost_equals(c_token, "ca$rtesian"))
  749.         mapping3d = MAP3D_CARTESIAN;
  750.     else if (almost_equals(c_token, "s$pherical"))
  751.         mapping3d = MAP3D_SPHERICAL;
  752.     else if (almost_equals(c_token, "cy$lindrical"))
  753.         mapping3d = MAP3D_CYLINDRICAL;
  754.     else
  755.         int_error("expecting 'cartesian', 'spherical', or 'cylindrical'", c_token);
  756.     c_token++;
  757.     } else if (almost_equals(c_token,"co$ntour")) {
  758.     c_token++;
  759.     if (END_OF_COMMAND)
  760.         /* assuming same as points */
  761.         draw_contour = CONTOUR_BASE;
  762.     else {
  763.         if (almost_equals(c_token, "ba$se"))
  764.          draw_contour = CONTOUR_BASE;
  765.         else if (almost_equals(c_token, "s$urface"))
  766.         draw_contour = CONTOUR_SRF;
  767.         else if (almost_equals(c_token, "bo$th"))
  768.         draw_contour = CONTOUR_BOTH;
  769.         else
  770.         int_error("expecting 'base', 'surface', or 'both'", c_token);
  771.         c_token++;
  772.     }
  773.     } else if (almost_equals(c_token,"noco$ntour")) {
  774.     c_token++;
  775.     draw_contour = CONTOUR_NONE;
  776.     } else if (almost_equals(c_token,"cntrp$aram")) {
  777.     struct value a;
  778.  
  779.     c_token++;
  780.     if (END_OF_COMMAND) {
  781.         /* assuming same as defaults */
  782.         contour_pts = 5;
  783.         contour_kind = CONTOUR_KIND_LINEAR;
  784.         contour_order = 4;
  785.         contour_levels = 5;
  786.          levels_kind = LEVELS_AUTO;
  787.     } else if (almost_equals(c_token, "p$oints")) {
  788.         c_token++;
  789.         contour_pts = (int) real(const_express(&a));
  790.     } else if (almost_equals(c_token, "li$near")) {
  791.         c_token++;
  792.         contour_kind = CONTOUR_KIND_LINEAR;
  793.     } else if (almost_equals(c_token, "c$ubicspline")) {
  794.         c_token++;
  795.         contour_kind = CONTOUR_KIND_CUBIC_SPL;
  796.     } else if (almost_equals(c_token, "b$spline")) {
  797.         c_token++;
  798.         contour_kind = CONTOUR_KIND_BSPLINE;
  799.     } else if (almost_equals(c_token, "le$vels")) {
  800.         int i = 0;  /* local counter */
  801.         c_token++;
  802.         /*  RKC: I have modified the next two:
  803.          *   to use commas to separate list elements as in xtics
  804.          *   so that incremental lists start,incr[,end]as in "
  805.          */
  806.         if (almost_equals(c_token, "di$screte")) {
  807.         levels_kind = LEVELS_DISCRETE;
  808.         c_token++;
  809.         if(END_OF_COMMAND)
  810.             int_error("expecting discrete level", c_token);
  811.         else
  812.             levels_list[i++] = real(const_express(&a));
  813.  
  814.         while(!END_OF_COMMAND) {
  815.             if (!equals(c_token, ","))
  816.             int_error("expecting comma to separate discrete levels", c_token);
  817.             c_token++;
  818.             levels_list[i++] = real(const_express(&a));
  819.         }
  820.         contour_levels = i;
  821.         } else if (almost_equals(c_token, "in$cremental")) {
  822.         levels_kind = LEVELS_INCREMENTAL;
  823.         c_token++;
  824.         levels_list[i++] = real(const_express(&a));
  825.         if (!equals(c_token, ","))
  826.             int_error("expecting comma to separate start,incr levels", c_token);
  827.         c_token++;
  828.         if((levels_list[i++] = real(const_express(&a))) == 0)
  829.             int_error("increment cannot be 0", c_token);
  830.         if(!END_OF_COMMAND) {
  831.             if (!equals(c_token, ","))
  832.             int_error("expecting comma to separate incr,stop levels", c_token);
  833.             c_token++;
  834.             /* need to round up, since 10,10,50 is 5 levels, not four,
  835.              * but 10,10,49 is four
  836.              */
  837.             contour_levels = (int) ( (real(const_express(&a))-levels_list[0])/levels_list[1] + 1.0);
  838.         }
  839.         } else if (almost_equals(c_token, "au$to")) {
  840.         levels_kind = LEVELS_AUTO;
  841.         c_token++;
  842.         if(!END_OF_COMMAND)
  843.             contour_levels = (int) real(const_express(&a));
  844.         } else {
  845.         if(levels_kind == LEVELS_DISCRETE)
  846.             int_error("Levels type is discrete, ignoring new number of contour levels", c_token);
  847.         contour_levels = (int) real(const_express(&a));
  848.         }
  849.     } else if (almost_equals(c_token, "o$rder")) {
  850.         int order;
  851.         c_token++;
  852.         order = (int) real(const_express(&a));
  853.         if ( order < 2 || order > 10 )
  854.         int_error("bspline order must be in [2..10] range.", c_token);
  855.         contour_order = order;
  856.     } else
  857.         int_error("expecting 'linear', 'cubicspline', 'bspline', 'points', 'levels' or 'order'", c_token);
  858.     } else if (almost_equals(c_token,"da$ta")) {
  859.     c_token++;
  860.     if (!almost_equals(c_token,"s$tyle"))
  861.         int_error("expecting keyword 'style'",c_token);
  862.     data_style = get_style();
  863.     } else if (almost_equals(c_token,"dg$rid3d")) {
  864.     int i;
  865.     TBOOLEAN was_comma = TRUE;
  866.     int local_vals[3];
  867.     struct value a;
  868.  
  869.     local_vals[0] = dgrid3d_row_fineness;
  870.     local_vals[1] = dgrid3d_col_fineness;
  871.     local_vals[2] = dgrid3d_norm_value;
  872.     c_token++;
  873.     for (i = 0; i < 3 && !(END_OF_COMMAND);) {
  874.         if (equals(c_token,",")) {
  875.         if (was_comma) i++;
  876.             was_comma = TRUE;
  877.         c_token++;
  878.         } else {
  879.         if (!was_comma)
  880.             int_error("',' expected",c_token);
  881.         local_vals[i] = real(const_express(&a));
  882.         i++;
  883.         was_comma = FALSE;
  884.         }
  885.     }
  886.  
  887.     if (local_vals[0] < 2 || local_vals[0] > 1000)
  888.         int_error("Row size must be in [2:1000] range; size unchanged",
  889.               c_token);
  890.     if (local_vals[1] < 2 || local_vals[1] > 1000)
  891.         int_error("Col size must be in [2:1000] range; size unchanged",
  892.               c_token);
  893.     if (local_vals[2] < 1 || local_vals[2] > 100)
  894.         int_error("Norm must be in [1:100] range; norm unchanged", c_token);
  895.  
  896.     dgrid3d_row_fineness = local_vals[0];
  897.     dgrid3d_col_fineness = local_vals[1];
  898.     dgrid3d_norm_value = local_vals[2];
  899.     dgrid3d = TRUE;
  900.     } else if (almost_equals(c_token,"nodg$rid3d")) {
  901.     c_token++;
  902.     dgrid3d = FALSE;
  903.     } else if (almost_equals(c_token,"mis$sing")) {
  904.     c_token++;
  905.     if (END_OF_COMMAND) {
  906.         if (missing_val)
  907.         free(missing_val);
  908.         missing_val = NULL;
  909.     } else {
  910.         if (!isstring(c_token))
  911.         int_error("Expected missing-value string", c_token);
  912.         m_quote_capture(&missing_val, c_token, c_token);
  913.         c_token++;
  914.     }
  915.     } else if (almost_equals(c_token,"nomis$sing")) {
  916.     ++c_token;
  917.     if (missing_val)
  918.         free(missing_val);
  919.     missing_val = NULL;
  920.     } else if (almost_equals(c_token,"du$mmy")) {
  921.     c_token++;
  922.     if (END_OF_COMMAND)
  923.         int_error("expecting dummy variable name", c_token);
  924.     else {
  925.         if (!equals(c_token,","))
  926.         copy_str(dummy_var[0],c_token++, MAX_ID_LEN);
  927.         if (!END_OF_COMMAND && equals(c_token,",")) {
  928.         c_token++;
  929.         if (END_OF_COMMAND)
  930.             int_error("expecting second dummy variable name", c_token);
  931.         copy_str(dummy_var[1],c_token++, MAX_ID_LEN);
  932.         }
  933.     }
  934.     } else if (almost_equals(c_token,"fo$rmat")) {
  935.     TBOOLEAN setx = FALSE, sety = FALSE, setz = FALSE;
  936.     TBOOLEAN setx2 = FALSE, sety2 = FALSE;
  937.     c_token++;
  938.     if (equals(c_token,"x")) {
  939.         setx = TRUE;
  940.         c_token++;
  941.     } else if (equals(c_token,"y")) {
  942.         sety = TRUE;
  943.         c_token++;
  944.     } else if (equals(c_token,"x2")) {
  945.         setx2 = TRUE;
  946.         c_token++;
  947.     } else if (equals(c_token,"y2")) {
  948.         sety2 = TRUE;
  949.         c_token++;
  950.     } else if (equals(c_token,"z")) {
  951.         setz = TRUE;
  952.         c_token++;
  953.     } else if (equals(c_token,"xy") || equals(c_token,"yx")) {
  954.         setx = sety = TRUE;
  955.         c_token++;
  956.     } else if (isstring(c_token) || END_OF_COMMAND) {
  957.         /* Assume he wants all */
  958.         setx = sety = setz = setx2 = sety2 = TRUE;
  959.     }
  960.  
  961.     if (END_OF_COMMAND) {
  962.         if (setx) {
  963.         (void) strcpy(xformat,DEF_FORMAT);
  964.         format_is_numeric[FIRST_X_AXIS] = 1;
  965.         }
  966.         if (sety) {
  967.         (void) strcpy(yformat,DEF_FORMAT);
  968.         format_is_numeric[FIRST_Y_AXIS] = 1;
  969.         }
  970.         if (setz) {
  971.         (void) strcpy(zformat,DEF_FORMAT);
  972.         format_is_numeric[FIRST_Z_AXIS] = 1;
  973.         }
  974.         if (setx2) {
  975.         (void) strcpy(x2format,DEF_FORMAT);
  976.         format_is_numeric[SECOND_X_AXIS] = 1;
  977.         }
  978.         if (sety2) {
  979.         (void) strcpy(y2format,DEF_FORMAT);
  980.         format_is_numeric[SECOND_Y_AXIS] = 1;
  981.         }
  982.     } else {
  983.         if (!isstring(c_token))
  984.         int_error("expecting format string",c_token);
  985.         else {
  986.         if (setx) {
  987.             quote_str(xformat,c_token, MAX_ID_LEN);
  988.             format_is_numeric[FIRST_X_AXIS] = looks_like_numeric(xformat);
  989.         }
  990.         if (sety) {
  991.             quote_str(yformat,c_token, MAX_ID_LEN);
  992.             format_is_numeric[FIRST_Y_AXIS] = looks_like_numeric(yformat);
  993.         }
  994.         if (setz) {
  995.             quote_str(zformat,c_token, MAX_ID_LEN);
  996.             format_is_numeric[FIRST_Z_AXIS] =looks_like_numeric(zformat);
  997.         }
  998.         if (setx2) {
  999.             quote_str(x2format,c_token, MAX_ID_LEN);
  1000.             format_is_numeric[SECOND_X_AXIS] = looks_like_numeric(x2format);
  1001.         }
  1002.         if (sety2) {
  1003.             quote_str(y2format,c_token, MAX_ID_LEN);
  1004.             format_is_numeric[SECOND_Y_AXIS] = looks_like_numeric(y2format);
  1005.         }
  1006.         c_token++;
  1007.         }
  1008.     }
  1009.     } else if (almost_equals(c_token,"fu$nction")) {
  1010.     c_token++;
  1011.     if (!almost_equals(c_token,"s$tyle"))
  1012.         int_error("expecting keyword 'style'",c_token);
  1013.     func_style = get_style();
  1014.     } else if (almost_equals(c_token,"la$bel")) {
  1015.     c_token++;
  1016.     set_label();
  1017.     } else if (almost_equals(c_token,"nola$bel")) {
  1018.     c_token++;
  1019.     set_nolabel();
  1020.     } else if (almost_øÄ
  1021. li$nestyle") || equals(c_token, "ls" )) {
  1022.     c_token++;
  1023.     set_linestyle();
  1024.     } else if (almost_equals(c_token,"noli$nestyle") || equals(c_token, "nols" )) {
  1025.     c_token++;
  1026.     set_nolinestyle();
  1027.     } else if (almost_equals(c_token,"lo$gscale")) {
  1028.     c_token++;
  1029.     if (END_OF_COMMAND) {
  1030.         is_log_x = is_log_y = is_log_z = is_log_x2 = is_log_y2 = TRUE;
  1031.         base_log_x = base_log_y = base_log_z = base_log_x2 = base_log_y2 = 10.0;
  1032.         log_base_log_x = log_base_log_y = log_base_log_z = log_base_log_x2 = log_base_log_y2 = M_LN10;
  1033.     } else {
  1034.         TBOOLEAN change_x = FALSE;
  1035.         TBOOLEAN change_y = FALSE;
  1036.         TBOOLEAN change_z = FALSE;
  1037.         TBOOLEAN change_x2 = FALSE;
  1038.         TBOOLEAN change_y2 = FALSE;
  1039.         double newbase = 10, log_newbase;
  1040.  
  1041.         if (equals(c_token, "x2"))
  1042.         change_x2 = TRUE;
  1043.         else if (equals(c_token, "y2"))
  1044.         change_y2 = TRUE;
  1045.         else { /* must not see x when x2, etc */
  1046.         if (chr_in_str(c_token, 'x'))
  1047.             change_x = TRUE;
  1048.         if (chr_in_str(c_token, 'y'))
  1049.             change_y = TRUE;
  1050.         if (chr_in_str(c_token, 'z'))
  1051.             change_z = TRUE;
  1052.         }
  1053.         c_token++;
  1054.         if (!END_OF_COMMAND) {
  1055.         struct value a;
  1056.         newbase = magnitude(const_express(&a));
  1057.         if (newbase < 1.1)
  1058.             int_error("log base must be >= 1.1; logscale unchanged",
  1059.         c_token);
  1060.         }
  1061.         log_newbase = log(newbase);
  1062.  
  1063.         if (change_x) {
  1064.         is_log_x = TRUE;
  1065.         base_log_x = newbase;
  1066.         log_base_log_x = log_newbase;
  1067.         }
  1068.         if (change_y) {
  1069.         is_log_y = TRUE;
  1070.         base_log_y = newbase;
  1071.         log_base_log_y = log_newbase;
  1072.         }
  1073.         if (change_z) {
  1074.         is_log_z = TRUE;
  1075.         base_log_z = newbase;
  1076.         log_base_log_z = log_newbase;
  1077.         }
  1078.         if (change_x2) {
  1079.         is_log_x2 = TRUE;
  1080.         base_log_x2 = newbase;
  1081.         log_base_log_x2 = log_newbase;
  1082.         }
  1083.         if (change_y2) {
  1084.         is_log_y2 = TRUE;
  1085.         base_log_y2 = newbase;
  1086.         log_base_log_y2 = log_newbase;
  1087.         }
  1088.     }
  1089.     } else if (almost_equals(c_token,"nolo$gscale")) {
  1090.     c_token++;
  1091.     if (END_OF_COMMAND) {
  1092.         is_log_x = is_log_y = is_log_z = is_log_x2 = is_log_y2 = FALSE;
  1093.     } else if (equals(c_token, "x2")) {
  1094.         is_log_x2 = FALSE; ++c_token;
  1095.     } else if (equals(c_token, "y2")) {
  1096.         is_log_y2 = FALSE; ++c_token;
  1097.     } else {
  1098.         if (chr_in_str(c_token, 'x')) {
  1099.         is_log_x = FALSE;
  1100.         base_log_x = 0.0;
  1101.         log_base_log_x = 0.0;
  1102.         }
  1103.         if (chr_in_str(c_token, 'y')) {
  1104.         is_log_y = FALSE;
  1105.         base_log_y = 0.0;
  1106.         log_base_log_y = 0.0;
  1107.         }
  1108.         if (chr_in_str(c_token, 'z')) {
  1109.         is_log_z = FALSE;
  1110.         base_log_z = 0.0;
  1111.         log_base_log_z = 0.0;
  1112.         }
  1113.         c_token++;
  1114.     }
  1115.     } else if (almost_equals(c_token,"of$fsets")) {
  1116.     c_token++;
  1117.     if (END_OF_COMMAND) {
  1118.         loff = roff = toff = boff = 0.0;  /* Reset offsets */
  1119.     } else {
  1120.         load_offsets (&loff,&roff,&toff,&boff);
  1121.     }
  1122.     } else if (almost_equals(c_token, "noof$fsets")) {
  1123.     loff = roff = toff = boff = 0.0;
  1124.     ++c_token;
  1125.     } else if(almost_equals(c_token,"b$ars")) {
  1126.     c_token++;
  1127.     if(END_OF_COMMAND) {
  1128.         bar_size = 1.0;
  1129.     } else if(almost_equals(c_token,"s$mall")) {
  1130.         bar_size = 0.0;
  1131.         ++c_token;
  1132.     } else if(almost_equals(c_token,"l$arge")) {
  1133.         bar_size = 1.0;
  1134.         ++c_token;
  1135.     } else {
  1136.         struct value a;
  1137.         bar_size = real(const_express(&a));
  1138.     }
  1139.     } else if (almost_equals(c_token, "nob$ars")) {
  1140.     ++c_token;
  1141.     bar_size = 0.0;
  1142.     } else if (almost_equals(c_token, "enco$ding")) {
  1143.     c_token++;
  1144.     if(END_OF_COMMAND) {
  1145.         encoding = ENCODING_DEFAULT;
  1146.     } else if (almost_equals(c_token,"def$ault")) {
  1147.         c_token++;
  1148.         encoding = ENCODING_DEFAULT;
  1149.     } else if (almost_equals(c_token,"iso$_8859_1")) {
  1150.         c_token++;
  1151.         encoding = ENCODING_ISO_8859_1;
  1152.     } else if (almost_equals(c_token,"cp4$37")) {
  1153.         c_token++;
  1154.         encoding = ENCODING_CP_437;
  1155.     } else if (almost_equals(c_token,"cp8$50")) {
  1156.         c_token++;
  1157.         encoding = ENCODING_CP_850;
  1158.     } else {
  1159.         int_error("expecting one of 'default', 'iso_8859_1', 'cp437' or 'cp850'", c_token);
  1160.     }
  1161.     } else
  1162.     return(FALSE);  /* no command match */
  1163.  
  1164.     return(TRUE);
  1165. }
  1166.  
  1167.  
  1168. /* return TRUE if a command match, FALSE if not */
  1169. static TBOOLEAN
  1170. set_two()
  1171. {
  1172.     if (almost_equals(c_token,"o$utput")) {
  1173.     if (multiplot) {
  1174.         int_error("you can't change the output in multiplot mode", c_token);
  1175.     }
  1176.  
  1177.     c_token++;
  1178.     if (END_OF_COMMAND) {    /* no file specified */
  1179.          term_set_output(NULL);
  1180.          if (outstr) {
  1181.         free(outstr);
  1182.         outstr = NULL; /* means STDOUT */
  1183.         }
  1184.     } else if (!isstring(c_token)) {
  1185.         int_error("expecting filename",c_token);
  1186.     } else {
  1187.         /* on int_error, we'd like to remember that this is allocated */
  1188.         static char *testfile = NULL;
  1189.         m_quote_capture(&testfile,c_token, c_token); /* reallocs store */
  1190.         /* Skip leading whitespace */
  1191.         while (isspace((int)*testfile))
  1192.         testfile++;
  1193.         ++c_token;
  1194.         term_set_output(testfile);
  1195.         /* if we get here then it worked, and outstr now = testfile */
  1196.         testfile = NULL;
  1197.     }
  1198.     } else if (almost_equals(c_token,"origin")) {
  1199.     struct value s;
  1200.     c_token++;
  1201.     if (END_OF_COMMAND) {
  1202.         xoffset = 0.0;
  1203.         yoffset = 0.0;
  1204.     } else {
  1205.         xoffset = real(const_express(&s));
  1206.         if (!equals(c_token,","))
  1207.         int_error("',' expected",c_token);
  1208.         c_token++;
  1209.         yoffset = real(const_express(&s));
  1210.     } 
  1211.     } else if (almost_equals(c_token,"tit$le")) {
  1212.     set_xyzlabel(&title);
  1213.     } else if (almost_equals(c_token,"xl$abel")) {
  1214.     set_xyzlabel(&xlabel);
  1215.     } else if (almost_equals(c_token,"yl$abel")) {
  1216.     set_xyzlabel(&ylabel);
  1217.     } else if (almost_equals(c_token,"zl$abel")) {
  1218.     set_xyzlabel(&zlabel);
  1219.     } else if (almost_equals(c_token,"x2l$abel")) {
  1220.     set_xyzlabel(&x2label);
  1221.     } else if (almost_equals(c_token,"y2l$abel")) {
  1222.     set_xyzlabel(&y2label);
  1223.     } else if (almost_equals(c_token,"keyt$itle")) {
  1224.     c_token++;
  1225.     if (END_OF_COMMAND) {    /* set to default */
  1226.         key_title[0] = NUL;
  1227.     } else {
  1228.         if (isstring(c_token)) {
  1229.         /* We have string specified - grab it. */
  1230.         quote_str(key_title,c_token, MAX_LINE_LEN);
  1231.         c_token++;
  1232.         }
  1233.         /* c_token++; */
  1234.     }
  1235.     } else if (almost_equals(c_token, "nokeyt$itle")) {
  1236.     ++c_token;
  1237.     *key_title = 0;
  1238.     } else if (almost_equals(c_token,"timef$mt")) {
  1239.     c_token++;
  1240.     if (END_OF_COMMAND) {    /* set to default */
  1241.         strcpy(timefmt,TIMEFMT);
  1242.     } else {
  1243.         if (isstring(c_token)) {
  1244.         /* We have string specified - grab it. */
  1245.         quote_str(timefmt,c_token, 25);
  1246.         }
  1247.         c_token++;
  1248.     }
  1249.     } else if (almost_equals(c_token,"loc$ale")) {
  1250.     c_token++;
  1251.     if (END_OF_COMMAND) {
  1252.         set_locale("C");
  1253.     } else if (isstring(c_token)) {
  1254.         char ss[MAX_ID_LEN+1];
  1255.         quote_str(ss,c_token,MAX_ID_LEN);
  1256.         set_locale(ss);
  1257.         ++c_token;
  1258.     } else {
  1259.         int_error("Expected string", c_token);
  1260.     }
  1261.     }
  1262.  
  1263. #define DO_ZEROAX(variable, string,neg) \
  1264. else if (almost_equals(c_token, string)) { \
  1265.    ++c_token; if (END_OF_COMMAND) variable.l_type = -1; \
  1266.    else { \
  1267.       struct value a; \
  1268.       int old_token = c_token;\
  1269.       LP_PARSE(variable,1,0,-1,0); \
  1270.       if (old_token == c_token) \
  1271.          variable.l_type = real(const_express(&a)) - 1; \
  1272.    }\
  1273. } else if (almost_equals(c_token, neg)) { \
  1274.    ++c_token; variable.l_type = -3; \
  1275. }
  1276.  
  1277.     DO_ZEROAX(xzeroaxis, "xzero$axis", "noxzero$axis")
  1278.     DO_ZEROAX(yzeroaxis, "yzero$axis", "noyzero$axis")
  1279.     DO_ZEROAX(x2zeroaxis, "x2zero$axis", "nox2zero$axis")
  1280.     DO_ZEROAX(y2zeroaxis, "y2zero$axis", "noy2zero$axis")
  1281.  
  1282.     else if (almost_equals(c_token,"zeroa$xis")) {
  1283.     c_token++;
  1284.     LP_PARSE(xzeroaxis,1,0,-1,0);
  1285.     memcpy(&yzeroaxis,&xzeroaxis,sizeof(struct lp_style_type));
  1286.     } else if (almost_equals(c_token,"nozero$axis")) {
  1287.     c_token++;
  1288.     xzeroaxis.l_type  = -3;
  1289.     yzeroaxis.l_type  = -3;
  1290.     x2zeroaxis.l_type = -3;
  1291.     y2zeroaxis.l_type = -3;
  1292.     } else if (almost_equals(c_token,"par$ametric")) {
  1293.     if (!parametric) {
  1294.         parametric = TRUE;
  1295.         if (!polar) { /* already done for polar */
  1296.         strcpy (dummy_var[0], "t");
  1297.         strcpy (dummy_var[1], "y");
  1298.         if (interactive)
  1299.              (void) fprintf(stderr,"\n\tdummy variable is t for curves, u/v for surfaces\n");
  1300.         }
  1301.     }
  1302.     c_token++;
  1303.     } else if (almost_equals(c_token,"nopar$ametric")) {
  1304.     if (parametric) {
  1305.         parametric = FALSE;
  1306.         if (!polar) { /* keep t for polar */
  1307.         strcpy (dummy_var[0], "x");
  1308.         strcpy (dummy_var[1], "y");
  1309.         if (interactive)
  1310.            (void) fprintf(stderr,"\n\tdummy variable is x for curves, x/y for surfaces\n");
  1311.         }
  1312.     }
  1313.     c_token++;
  1314.     } else if (almost_equals(c_token, "poi$ntsize")) {
  1315.     struct value a;
  1316.     c_token++;
  1317.     if (END_OF_COMMAND)
  1318.        pointsize = 1.0;
  1319.     else
  1320.         pointsize = real(const_express(&a));
  1321.     if(pointsize <= 0) pointsize = 1;
  1322.     } else if (almost_equals(c_token,"pol$ar")) {
  1323.     if (!polar) {
  1324.         if (!parametric) {
  1325.         if (interactive)
  1326.             (void) fprintf(stderr,"\n\tdummy variable is t for curves\n");
  1327.         strcpy (dummy_var[0], "t");
  1328.         }
  1329.         polar = TRUE;
  1330.         if (autoscale_t) {
  1331.         /* only if user has not set a range manually */
  1332.         tmin = 0.0;
  1333.         tmax = 2*Pi / ang2rad;  /* 360 if degrees, 2pi if radians */
  1334.         }
  1335.     }
  1336.     c_token++;
  1337.     } else if (almost_equals(c_token,"nopo$lar")) {
  1338.     if (polar) {
  1339.         polar = FALSE;
  1340.         if (parametric && autoscale_t) {
  1341.         /* only if user has not set an explicit range */
  1342.         tmin = -5.0;
  1343.         tmax = 5.0;
  1344.         }
  1345.         if (!parametric) {
  1346.         strcpy (dummy_var[0], "x");
  1347.         if (interactive)
  1348.             (void) fprintf(stderr,"\n\tdummy variable is x for curves\n");
  1349.         }
  1350.     }
  1351.     c_token++;
  1352.     } else if (almost_equals(c_token,"an$gles")) {
  1353.     c_token++;
  1354.     if (END_OF_COMMAND) {
  1355.         /* assuming same as defaults */
  1356.         angles_format = ANGLES_RADIANS;
  1357.         ang2rad = 1;
  1358.     } else if (almost_equals(c_token, "r$adians")) {
  1359.         angles_format = ANGLES_RADIANS;
  1360.         c_token++;
  1361.         ang2rad = 1;
  1362.     } else if (almost_equals(c_token, "d$egrees")) {
  1363.         angles_format = ANGLES_DEGREES;
  1364.         c_token++;
  1365.         ang2rad = DEG2RAD;
  1366.     } else
  1367.         int_error("expecting 'radians' or 'degrees'", c_token);
  1368.  
  1369.     if (polar && autoscale_t) {
  1370.         /* set trange if in polar mode and no explicit range */
  1371.         tmin = 0;
  1372.         tmax = 2*Pi/ang2rad;
  1373.     }
  1374.     }
  1375.  
  1376. #define GRID_MATCH(string, neg, mask) \
  1377. if (almost_equals(c_token, string)) { work_grid.l_type |= mask; ++c_token; } \
  1378. else if (almost_equals(c_token, neg)) { work_grid.l_type &= ~(mask); ++c_token; }
  1379.  
  1380.     else if (almost_equals(c_token,"g$rid")) {
  1381.     c_token++;
  1382.     if (END_OF_COMMAND && !work_grid.l_type)
  1383.         work_grid.l_type = GRID_X|GRID_Y;
  1384.     else
  1385.         while (!END_OF_COMMAND) {
  1386.         GRID_MATCH("x$tics", "nox$tics", GRID_X)
  1387.         else GRID_MATCH("y$tics", "noy$tics", GRID_Y)
  1388.         else GRID_MATCH("z$tics", "noz$tics", GRID_Z)
  1389.         else GRID_MATCH("x2$tics", "nox2$tics", GRID_X2)
  1390.         else GRID_MATCH("y2$tics", "noy2$tics", GRID_Y2)
  1391.         else GRID_MATCH("mx$tics", "nomx$tics", GRID_MX)
  1392.         else GRID_MATCH("my$tics", "nomy$tics", GRID_MY)
  1393.         else GRID_MATCH("mz$tics", "nomz$tics", GRID_MZ)
  1394.         else GRID_MATCH("mx2$tics", "nomx2$tics", GRID_MX2)
  1395.         else GRID_MATCH("my2$tics", "nomy2$tics", GRID_MY2)
  1396.         else if (almost_equals(c_token,"po$lar")) {
  1397.             if (!work_grid.l_type)
  1398.             work_grid.l_type = GRID_X;
  1399.             c_token++;
  1400.             if (END_OF_COMMAND) {
  1401.             polar_grid_angle = 30*DEG2RAD;
  1402.             } else {
  1403.             /* get radial interval */
  1404.             struct value a;
  1405.             polar_grid_angle = ang2rad*real(const_express(&a));
  1406.             }
  1407.         } else if (almost_equals(c_token,"nopo$lar")) {
  1408.             polar_grid_angle = 0; /* not polar grid */
  1409.             c_token++;
  1410.         } else
  1411.             break; /* might be a linetype */
  1412.         }
  1413.  
  1414.     if (!END_OF_COMMAND) {
  1415.         struct value a;
  1416.         int old_token = c_token;
  1417.  
  1418.         LP_PARSE(grid_lp,1,0,-1,1);
  1419.         if (c_token == old_token) { /* nothing parseable found... */
  1420.         grid_lp.l_type = real(const_express(&a)) - 1;
  1421.         }
  1422.             
  1423.         if (!work_grid.l_type)
  1424.         work_grid.l_type = GRID_X|GRID_Y;
  1425.         /* probably just  set grid <linetype> */
  1426.  
  1427.         if (END_OF_COMMAND) {
  1428.         memcpy(&mgrid_lp,&grid_lp,sizeof(struct lp_style_type));
  1429.         } else {
  1430.         if (equals(c_token,",")) 
  1431.             c_token++;
  1432.         old_token = c_token;
  1433.         LP_PARSE(mgrid_lp,1,0,-1,1);
  1434.         if (c_token == old_token) {
  1435.             mgrid_lp.l_type = real(const_express(&a)) -1;
  1436.         }
  1437.         }
  1438.  
  1439.         if (!work_grid.l_type)
  1440.         work_grid.l_type = GRID_X|GRID_Y;
  1441.         /* probably just  set grid <linetype> */
  1442.     }
  1443.  
  1444.     } else if (almost_equals(c_token,"nog$rid")) {
  1445.     work_grid.l_type = GRID_OFF;
  1446.     c_token++;
  1447.     } else if (almost_equals(c_token,"su$rface")) {
  1448.     draw_surface = TRUE;
  1449.     c_token++;
  1450.     } else if (almost_equals(c_token,"nosu$rface")) {
  1451.     draw_surface = FALSE;
  1452.     c_token++;
  1453.     } else if (almost_equals(c_token,"bor$der")) {
  1454.     struct value a;
  1455.     c_token++;
  1456.     if(END_OF_COMMAND){
  1457.         draw_border = 31;
  1458.     } else {
  1459.         draw_border = (int)real(const_express(&a));
  1460.     }
  1461.     /* HBB 980609: add linestyle handling for 'set border...' */
  1462.     /* For now, you have to give a border bitpattern to be able to specify a linestyle. Sorry for this,
  1463.      * but the gnuplot parser really is too messy for any other solution, currently */
  1464.     if(END_OF_COMMAND) {
  1465.         set_lp_properties(&border_lp, 0, -2, 0, 1.0, 1.0);
  1466.     } else {
  1467.         LP_PARSE(border_lp, 1, 0, -2, 0);
  1468.     }
  1469.     } else if (almost_equals(c_token,"k$ey")) {
  1470.     struct value a;
  1471.     c_token++;
  1472.     if (END_OF_COMMAND) {
  1473.         key = -1;
  1474.         key_vpos = TTOP;
  1475.         key_hpos = TRIGHT;
  1476.         key_just = JRIGHT;
  1477.         key_reverse = FALSE;
  1478.         set_lp_properties(&key_box,0,-3,0,1.0,1.0);
  1479.         key_swidth = 4;
  1480.         key_vert_factor = 1;
  1481.         key_width_fix = 0;
  1482.         key_title[0] = 0;
  1483.     } else {
  1484.         while (!END_OF_COMMAND) {
  1485.         if (almost_equals(c_token,"t$op")) {
  1486.             key_vpos = TTOP;
  1487.             key = -1;
  1488.         } else if (almost_equals(c_token,"b$ottom")) {
  1489.             key_vpos = TBOTTOM;
  1490.             key = -1;
  1491.         } else if (almost_equals(c_token,"l$eft")) {
  1492.             key_hpos = TLEFT;
  1493.             /* key_just = TRIGHT; */
  1494.             key = -1;
  1495.         } else if (almost_equals(c_token,"r$ight")) {
  1496.             key_hpos = TRIGHT;
  1497.             key = -1;
  1498.         } else if (almost_equals(c_token,"u$nder") ||
  1499.                almost_equals(c_token,"be$low")) {
  1500.             key_vpos = TUNDER;
  1501.             if (key_hpos == TOUT)
  1502.             key_hpos--;
  1503.             key = -1;
  1504.         } else if (almost_equals(c_token,"o$utside")) {
  1505.             key_hpos = TOUT;
  1506.             if (key_vpos == TUNDER)
  1507.             key_vpos--;
  1508.             key = -1;
  1509.         } else if (almost_equals(c_token,"L$eft")) {
  1510.             /* key_hpos = TLEFT; */
  1511.             key_just = JLEFT;
  1512.             /* key = -1; */
  1513.         } else if (almost_equals(c_token,"R$ight")) {
  1514.             /* key_hpos = TLEFT; */
  1515.             key_just = JRIGHT;
  1516.             /* key = -1; */
  1517.         } else if (almost_equals(c_token,"rev$erse")) {
  1518.             key_reverse = TRUE;
  1519.         } else if (almost_equals(c_token,"norev$erse")) {
  1520.             key_reverse = FALSE;
  1521.         } else if (equals(c_token,"box")) {
  1522.             ++c_token;
  1523.             if (END_OF_COMMAND)
  1524.             key_box.l_type = -2;
  1525.             else {
  1526.             int old_token = c_token;
  1527.     
  1528.             LP_PARSE(key_box,1,0,-2,0);
  1529.             if (old_token == c_token) {
  1530.                 key_box.l_type = real(const_express(&a)) -1;
  1531.             }
  1532.             }        
  1533.             --c_token;  /* is incremented after loop */
  1534.         } else if (almost_equals(c_token,"nob$ox")) {
  1535.             key_box.l_type = -3;
  1536.         } else if (almost_equals(c_token, "sa$mplen")) {
  1537.             ++c_token;
  1538.             key_swidth = real(const_express(&a));
  1539.             --c_token; /* it is incremented after loop */
  1540.         } else if (almost_equals(c_token, "sp$acing")) {
  1541.             ++c_token;
  1542.             key_vert_factor = real(const_express(&a));
  1543.             if (key_vert_factor < 0.0)
  1544.             key_vert_factor = 0.0;
  1545.             --c_token; /* it is incremented after loop */
  1546.         } else if (almost_equals(c_token, "w$idth")) {
  1547.             ++c_token;
  1548.             key_width_fix = real(const_express(&a));
  1549.             --c_token; /* it is incremented after loop */
  1550.         } else if (almost_equals(c_token,"ti$tle")) {
  1551.             if (isstring(c_token+1)) {
  1552.             /* We have string specified - grab it. */
  1553.             quote_str(key_title,++c_token, MAX_LINE_LEN);
  1554.             }
  1555.             else
  1556.             key_title[0] = 0;
  1557.         } else {
  1558.             get_position(&key_user_pos);
  1559.             key = 1;
  1560.             --c_token;  /* will be incremented again soon */
  1561.         } 
  1562.         c_token++;
  1563.          } 
  1564.     }
  1565.     } else if (almost_equals(c_token,"nok$ey")) {
  1566.     key = 0;
  1567.     c_token++;
  1568.     } else if (almost_equals(c_token,"tic$s")) {
  1569.     tic_in = TRUE;
  1570.     c_token++;
  1571.     if (almost_equals(c_token,"i$n")) {
  1572.         tic_in = TRUE;
  1573.         c_token++;
  1574.     } else if (almost_equals(c_token,"o$ut")) {
  1575.         tic_in = FALSE;
  1576.         c_token++;
  1577.     }
  1578.     } else if (almost_equals(c_token,"xda$ta")) {
  1579.     c_token++;
  1580.     if(END_OF_COMMAND) {
  1581.         datatype[FIRST_X_AXIS] = FALSE;
  1582.         /* eh ? - t and u have nothing to do with x */
  1583.         datatype[T_AXIS] = FALSE;
  1584.         datatype[U_AXIS] = FALSE;
  1585.     } else {
  1586.         if (almost_equals(c_token,"t$ime")) {
  1587.         datatype[FIRST_X_AXIS] = TIME;
  1588.         datatype[T_AXIS] = TIME;
  1589.         datatype[U_AXIS] = TIME;
  1590.         } else {
  1591.         datatype[FIRST_X_AXIS] = FALSE;
  1592.         datatype[T_AXIS] = FALSE;
  1593.         datatype[U_AXIS] = FALSE;
  1594.         }
  1595.         c_token++;
  1596.     }
  1597.     } else if (almost_equals(c_token,"yda$ta")) {
  1598.     c_token++;
  1599.     if(END_OF_COMMAND) {
  1600.         datatype[FIRST_Y_AXIS] = FALSE;
  1601.         datatype[V_AXIS] = FALSE;
  1602.     } else {
  1603.         if (almost_equals(c_token,"t$ime")) {
  1604.         datatype[FIRST_Y_AXIS] = TIME;
  1605.         datatype[V_AXIS] = TIME;
  1606.         } else {
  1607.         datatype[FIRST_Y_AXIS] = FALSE;
  1608.         datatype[V_AXIS] = FALSE;
  1609.         }
  1610.         c_token++;
  1611.     }
  1612.     } else if (almost_equals(c_token,"zda$ta")) {
  1613.     c_token++;
  1614.     if(END_OF_COMMAND) {
  1615.         datatype[FIRST_Z_AXIS] = FALSE;
  1616.     } else {
  1617.         if (almost_equals(c_token,"t$ime")) {
  1618.         datatype[FIRST_Z_AXIS] = TIME;
  1619.         } else {
  1620.         datatype[FIRST_Z_AXIS] = FALSE;
  1621.         }
  1622.         c_token++;
  1623.     }
  1624.     } else if (almost_equals(c_token,"x2da$ta")) {
  1625.     c_token++;
  1626.     if(END_OF_COMMAND) {
  1627.         datatype[SECOND_X_AXIS] = FALSE;
  1628.     } else {
  1629.         if (almost_equals(c_token,"t$ime")) {
  1630.         datatype[SECOND_X_AXIS] = TIME;
  1631.         } else {
  1632.         datatype[SECOND_X_AXIS] = FALSE;
  1633.         }
  1634.         c_token++;
  1635.     }
  1636.     } else if (almost_equals(c_token,"y2da$ta")) {
  1637.     c_token++;
  1638.     if(END_OF_COMMAND) {
  1639.         datatype[SECOND_Y_AXIS] = FALSE;
  1640.     } else {
  1641.         if (almost_equals(c_token,"t$ime")) {
  1642.         datatype[SECOND_Y_AXIS] = TIME;
  1643.         } else {
  1644.         datatype[SECOND_Y_AXIS] = FALSE;
  1645.         }
  1646.         c_token++;
  1647.     }
  1648.     }
  1649.  
  1650. /* to save duplicating code for x/y/z/x2/y2, make a macro
  1651.  * (should perhaps be a function ?)
  1652.  * unfortunately, string concatenation is not supported on all compilers,
  1653.  * so we have to explicitly include both 'on' and 'no' strings in
  1654.  * the args
  1655.  */
  1656.  
  1657. /* change to a function: lph 25.09.1998 */
  1658.  
  1659. #define PROCESS_TIC_COMMANDS  set_tic_prop
  1660.  
  1661.     else if 
  1662.     (PROCESS_TIC_COMMANDS(&x2tics, &mx2tics, &mx2tfreq, &x2ticdef, 
  1663.      SECOND_X_AXIS, &rotate_x2tics, "x2") );
  1664.     else if 
  1665.     (PROCESS_TIC_COMMANDS(&y2tics, &my2tics, &my2tfreq, &y2ticdef,
  1666.      SECOND_Y_AXIS, &rotate_y2tics, "y2") );
  1667.     else if
  1668.     (PROCESS_TIC_COMMANDS(&xtics,   &mxtics, &mxtfreq,  &xticdef,
  1669.      FIRST_X_AXIS, &rotate_xtics, "x") );
  1670.     else if
  1671.     (PROCESS_TIC_COMMANDS(&ytics,   &mytics, &mytfreq,  &yticdef, 
  1672.      FIRST_Y_AXIS, &rotate_ytics, "y") );
  1673.     else if 
  1674.     (PROCESS_TIC_COMMANDS(&ztics,   &mztics, &mztfreq,  &zticdef,
  1675.      FIRST_Z_AXIS, &rotate_ztics, "z") );
  1676.  
  1677.     else if (almost_equals(c_token,"ticsl$evel")) {
  1678.     double tlvl;
  1679.     struct value a;
  1680.  
  1681.     c_token++;
  1682.     /* is datatype 'time' relevant here ? */
  1683.     tlvl = real(const_express(&a));
  1684.     ticslevel = tlvl;
  1685.     }
  1686.  
  1687. #define PROCESS_MARGIN(variable, string) \
  1688. else if (almost_equals(c_token,string)) {\
  1689.  ++c_token; if (END_OF_COMMAND) variable = -1;\
  1690.  else { struct value a; variable = real(const_express(&a)); } \
  1691. }
  1692.  
  1693.     PROCESS_MARGIN(lmargin, "lmar$gin")
  1694.     PROCESS_MARGIN(bmargin, "bmar$gin")
  1695.     PROCESS_MARGIN(rmargin, "rmar$gin")
  1696.     PROCESS_MARGIN(tmargin, "tmar$gin")
  1697.  
  1698.     else
  1699.     return(FALSE);    /* no command match */
  1700.  
  1701.     return(TRUE);
  1702. }
  1703.  
  1704.  
  1705.  
  1706. /* return TRUE if a command match, FALSE if not */
  1707. static TBOOLEAN
  1708. set_three()
  1709. {
  1710.     if (almost_equals(c_token,"sa$mples")) {
  1711.     register int tsamp1, tsamp2;
  1712.     struct value a;
  1713.  
  1714.     c_token++;
  1715.     tsamp1 = (int)magnitude(const_express(&a));
  1716.     tsamp2 = tsamp1;
  1717.     if (!END_OF_COMMAND) {
  1718.         if (!equals(c_token,","))
  1719.         int_error("',' expected",c_token);
  1720.         c_token++;
  1721.         tsamp2 = (int)magnitude(const_express(&a));
  1722.     }
  1723.     if (tsamp1 < 2 || tsamp2 < 2)
  1724.         int_error("sampling rate must be > 1; sampling unchanged",c_token);
  1725.     else {
  1726.         register struct surface_points *f_3dp = first_3dplot;
  1727.  
  1728.         first_3dplot = NULL;
  1729.         sp_free(f_3dp);
  1730.  
  1731.         samples = tsamp1;
  1732.         samples_1 = tsamp1;
  1733.         samples_2 = tsamp2;
  1734.     }
  1735.     } else if (almost_equals(c_token,"isosa$mples")) {
  1736.     register int tsamp1, tsamp2;
  1737.     struct value a;
  1738.  
  1739.     c_token++;
  1740.     tsamp1 = (int)magnitude(const_express(&a));
  1741.     tsamp2 = tsamp1;
  1742.     if (!END_OF_COMMAND) {
  1743.         if (!equals(c_token,","))
  1744.         int_error("',' expected",c_token);
  1745.         c_token++;
  1746.         tsamp2 = (int)magnitude(const_express(&a));
  1747.     }
  1748.     if (tsamp1 < 2 || tsamp2 < 2)
  1749.         int_error("sampling rate must be > 1; sampling unchanged",c_token);
  1750.     else {
  1751.         register struct curve_points *f_p = first_plot;
  1752.         register struct surface_points *f_3dp = first_3dplot;
  1753.  
  1754.         first_plot = NULL;
  1755.         first_3dplot = NULL;
  1756.         cp_free(f_p);
  1757.         sp_free(f_3dp);
  1758.  
  1759.         iso_samples_1 = tsamp1;
  1760.         iso_samples_2 = tsamp2;
  1761.     }
  1762.     } else if (almost_equals(c_token,"si$ze")) {
  1763.     struct value s;
  1764.     c_token++;
  1765.     if (END_OF_COMMAND) {
  1766.         xsize = 1.0;
  1767.         ysize = 1.0;
  1768.     } else {
  1769.         if (almost_equals(c_token, "sq$uare")) {
  1770.         aspect_ratio = 1.0;
  1771.         ++c_token;
  1772.         } else if (almost_equals(c_token,"ra$tio")) {
  1773.         ++c_token;
  1774.         aspect_ratio = real(const_express(&s));
  1775.         } else if (almost_equals(c_token, "nora$tio") || almost_equals(c_token, "nosq$uare")) {
  1776.         aspect_ratio = 0.0;
  1777.         ++c_token;
  1778.         }
  1779.                     
  1780.         if (!END_OF_COMMAND) {
  1781.         xsize = real(const_express(&s));
  1782.         if (equals(c_token,",")) {
  1783.             c_token++;
  1784.             ysize = real(const_express(&s));
  1785.         } else {
  1786.             ysize = xsize;
  1787.         }
  1788.         }
  1789.     }
  1790.     } else if (almost_equals(c_token,"ticsc$ale")) {
  1791.     struct value tscl;
  1792.     c_token++;
  1793.     if (END_OF_COMMAND) {
  1794.         ticscale = 1.0;
  1795.         miniticscale = 0.5;
  1796.     } else {
  1797.         ticscale = real(const_express(&tscl));
  1798.         if (END_OF_COMMAND) {
  1799.         miniticscale = ticscale*0.5;
  1800.         } else {
  1801.         miniticscale = real(const_express(&tscl));
  1802.         }
  1803.     }
  1804.     } else if (almost_equals(c_token,"t$erminal")) {
  1805.     if (multiplot) {
  1806.          int_error("You can't change the terminal in multiplot mode", c_token);
  1807.     }
  1808.  
  1809.     c_token++;
  1810.     if (END_OF_COMMAND) {
  1811.         list_terms();
  1812.         screen_ok = FALSE;
  1813.     } else {
  1814.         term_reset();
  1815.         term = 0; /* in case set_term() fails */
  1816.         term = set_term(c_token);
  1817.         c_token++;
  1818.  
  1819.         /* get optional mode parameters
  1820.          * not all drivers reset the option string before
  1821.          * strcat-ing to it, so we reset it for them
  1822.          */
  1823.         *term_options = 0;
  1824.         if (term)
  1825.         (*term->options)();
  1826.         if (interactive && *term_options)
  1827.         fprintf(stderr,"Options are '%s'\n",term_options);
  1828.     }
  1829.     } else if (almost_equals(c_token,"tim$estamp")) {
  1830.     c_token++;
  1831.     if (END_OF_COMMAND || !isstring(c_token))
  1832.         strcpy(timelabel.text, DEFAULT_TIMESTAMP_FORMAT);
  1833.  
  1834.     if (!END_OF_COMMAND) {
  1835.         struct value a;
  1836.  
  1837.         if (isstring(c_token)) {
  1838.         /* we have a format string */
  1839.         quote_str(timelabel.text, c_token, MAX_LINE_LEN);
  1840.         ++c_token;
  1841.         } else {
  1842.         strcpy(timelabel.text, DEFAULT_TIMESTAMP_FORMAT);
  1843.         }
  1844.         if (almost_equals(c_token,"t$op")) {
  1845.         timelabel_bottom = FALSE;
  1846.             ++c_token;
  1847.         } else if (almost_equals(c_token, "b$ottom")) {
  1848.         timelabel_bottom = TRUE;
  1849.             ++c_token;
  1850.         }
  1851.         if (almost_equals(c_token,"r$otate")) {
  1852.         timelabel_rotate = TRUE;
  1853.             ++c_token;
  1854.         } else if (almost_equals(c_token, "n$orotate")) {
  1855.         timelabel_rotate = FALSE;
  1856.             ++c_token;
  1857.         }
  1858.         /* We have x,y offsets specified */
  1859.         if (!END_OF_COMMAND && !equals(c_token,","))
  1860.         timelabel.xoffset = real(const_express(&a));
  1861.         if (!END_OF_COMMAND && equals(c_token,",")) {
  1862.         c_token++;
  1863.         timelabel.yoffset = real(const_express(&a));
  1864.         }
  1865.         if (!END_OF_COMMAND && isstring(c_token)) {
  1866.         quote_str(timelabel.font, c_token, MAX_LINE_LEN);
  1867.         ++c_token;
  1868.         } else {
  1869.         *timelabel.font = 0;
  1870.         }
  1871.     }
  1872.     } else if (almost_equals(c_token,"not$imestamp")) {
  1873.     *timelabel.text = 0;
  1874.     c_token++;
  1875.     } else if (almost_equals(c_token,"vi$ew")) {
  1876.     int i;
  1877.     TBOOLEAN was_comma = TRUE;
  1878.     double local_vals[4];
  1879.     struct value a;
  1880.  
  1881.     local_vals[0] = surface_rot_x;
  1882.     local_vals[1] = surface_rot_z;
  1883.     local_vals[2] = surface_scale;
  1884.     local_vals[3] = surface_zscale;
  1885.     c_token++;
  1886.     for (i = 0; i < 4 && !(END_OF_COMMAND);) {
  1887.         if (equals(c_token,",")) {
  1888.         if (was_comma) i++;
  1889.             was_comma = TRUE;
  1890.         c_token++;
  1891.         } else {
  1892.         if (!was_comma)
  1893.             int_error("',' expected",c_token);
  1894.         local_vals[i] = real(const_express(&a));
  1895.         i++;
  1896.         was_comma = FALSE;
  1897.         }
  1898.     }
  1899.  
  1900.     if (local_vals[0] < 0 || local_vals[0] > 180)
  1901.         int_error("rot_x must be in [0:180] degrees range; view unchanged", c_token);
  1902.     if (local_vals[1] < 0 || local_vals[1] > 360)
  1903.         int_error("rot_z must be in [0:360] degrees range; view unchanged", c_token);
  1904.     if (local_vals[2] < 1e-6)
  1905.         int_error("scale must be > 0; view unchanged", c_token);
  1906.     if (local_vals[3] < 1e-6)
  1907.         int_error("zscale must be > 0; view unchanged", c_token);
  1908.  
  1909.     surface_rot_x = local_vals[0];
  1910.     surface_rot_z = local_vals[1];
  1911.     surface_scale = local_vals[2];
  1912.     surface_zscale = local_vals[3];
  1913.     }
  1914.  
  1915. /* to save replicated code, define a macro */
  1916. #define PROCESS_RANGE(AXIS,STRING, MIN, MAX, AUTO) \
  1917. else if (almost_equals(c_token, STRING)) { \
  1918.  if (!equals(++c_token,"[")) int_error("expecting '['",c_token); \
  1919.  c_token++; \
  1920.  AUTO = load_range(AXIS,&MIN,&MAX,AUTO); \
  1921.  if (!equals(c_token,"]")) int_error("expecting ']'",c_token); \
  1922.  c_token++; \
  1923.  if (almost_equals(c_token, "rev$erse")) { \
  1924.    ++c_token; range_flags[AXIS] |= RANGE_REVERSE;\
  1925.  } else if (almost_equals(c_token, "norev$erse")) { \
  1926.    ++c_token; range_flags[AXIS] &= ~RANGE_REVERSE;\
  1927.  } if (almost_equals(c_token, "wr$iteback")) { \
  1928.    ++c_token; range_flags[AXIS] |= RANGE_WRITEBACK;\
  1929.  } else if (almost_equals(c_token, "nowri$teback")) { \
  1930.    ++c_token; range_flags[AXIS] &= ~RANGE_WRITEBACK;\
  1931. }}
  1932.  
  1933.     PROCESS_RANGE(R_AXIS, "rr$ange", rmin, rmax, autoscale_r)
  1934.     PROCESS_RANGE(T_AXIS, "tr$ange", tmin, tmax, autoscale_t)
  1935.     PROCESS_RANGE(U_AXIS, "ur$ange", umin, umax, autoscale_u)
  1936.     PROCESS_RANGE(V_AXIS, "vr$ange", vmin, vmax, autoscale_v)
  1937.     PROCESS_RANGE(FIRST_X_AXIS, "xr$ange", xmin, xmax, autoscale_x)
  1938.     PROCESS_RANGE(FIRST_Y_AXIS, "yr$ange", ymin, ymax, autoscale_y)
  1939.     PROCESS_RANGE(FIRST_Z_AXIS, "zr$ange", zmin, zmax, autoscale_z)
  1940.     PROCESS_RANGE(SECOND_X_AXIS, "x2r$ange", x2min, x2max, autoscale_x2)
  1941.     PROCESS_RANGE(SECOND_Y_AXIS, "y2r$ange", y2min, y2max, autoscale_y2)
  1942.  
  1943.     else if (almost_equals(c_token,"z$ero")) {
  1944.     struct value a;
  1945.     c_token++;
  1946.     zero = magnitude(const_express(&a));
  1947.     } else if (almost_equals(c_token,"multi$plot")) {
  1948.     term_start_multiplot();
  1949.     c_token++;
  1950.     } else if (almost_equals(c_token,"nomulti$plot")) {
  1951.     term_end_multiplot();
  1952.     c_token++;
  1953.     } else
  1954.     return(FALSE);    /* no command match */
  1955.  
  1956.     return(TRUE);
  1957. }
  1958.  
  1959.  
  1960. /*********** Support functions for set_command ***********/
  1961.  
  1962. /*
  1963.  * The set.c PROCESS_TIC_PROP macro has the following characteristics:
  1964.  *   (a) options must in the correct order
  1965.  *   (b) 'set xtics' (no option) resets only the interval (FREQ)
  1966.  *       {it will also negate NO_TICS, see (d)} 
  1967.  *   (c) changing any property also resets the interval to automatic
  1968.  *   (d) set no[xy]tics; set [xy]tics changes border to nomirror, rather 
  1969.  *       than to the default, mirror.
  1970.  *   (e) effect of 'set no[]tics; set []tics border ...' is compiler
  1971.  *       dependent;  if '!(TICS)' is evaluated first, 'border' is an 
  1972.  *       undefined variable :-(
  1973.  *
  1974.  * This function replaces the macro, and introduces a new option
  1975.  * 'au$tofreq' to give somewhat different behaviour:
  1976.  *   (a) no change
  1977.  *   (b) 'set xtics' (no option) only affects NO_TICS;  'autofreq' resets 
  1978.  *       the interval calulation to automatic
  1979.  *   (c) the interval mode is not affected by changing some other option
  1980.  *   (d) if NO_TICS, set []tics will restore defaults (borders, mirror
  1981.  *       where appropriate)
  1982.  *   (e) if (NO_TICS), border option is processed.
  1983.  *
  1984.  *  A 'default' option could easily be added to reset all options to
  1985.  *  the initial values - mostly book-keeping.
  1986.  *
  1987.  *  To retain tic properties after setting no[]tics may also be
  1988.  *  straightforward (save value as negative), but requires changes
  1989.  *  in other code ( e.g. for  'if (xtics)', use 'if (xtics > 0)'
  1990.  */
  1991.  
  1992. static int set_tic_prop(TICS, MTICS, FREQ, tdef, AXIS, ROTATE, tic_side)
  1993. /*    generates PROCESS_TIC_PROP strings from tic_side, e.g. "x2" 
  1994.    STRING, NOSTRING, MONTH, NOMONTH, DAY, NODAY, MINISTRING, NOMINI
  1995.    "nox2t$ics"     "nox2m$tics"  "nox2d$tics"    "nomx2t$ics" 
  1996.  */
  1997.  
  1998. int *TICS, *MTICS, AXIS;
  1999. double *FREQ;
  2000. struct ticdef *tdef;
  2001. TBOOLEAN *ROTATE;
  2002. char *tic_side;
  2003.  
  2004.  
  2005. {
  2006.     int match = 0;        /* flag, set by matching a tic command */
  2007.     char nocmd[12];        /* fill w/ "no"+'tic_side'+suffix */
  2008.     char *cmdptr, *sfxptr;
  2009.  
  2010.     (void) strcpy(nocmd, "no");
  2011.     cmdptr = &nocmd[2];
  2012.     (void) strcpy(cmdptr, tic_side);
  2013.     sfxptr = &nocmd[strlen(nocmd)];
  2014.     (void) strcpy(sfxptr, "t$ics");    /* STRING */
  2015.  
  2016.     if (almost_equals(c_token, cmdptr)) {
  2017.     match = 1;
  2018.     if (almost_equals(++c_token, "ax$is")) {
  2019.         *TICS &= ~TICS_ON_BORDER;
  2020.         *TICS |= TICS_ON_AXIS;
  2021.         ++c_token;
  2022.     }
  2023.     /* if tics are off, reset to default (border) */
  2024.     if (*TICS == NO_TICS) {
  2025.         *TICS = TICS_ON_BORDER;
  2026.         if (!strcmp(tic_side, "x") || !strcmp(tic_side, "y")) {
  2027.         *TICS |= TICS_MIRROR;
  2028.         }
  2029.     }
  2030.     if (almost_equals(c_token, "bo$rder")) {
  2031.         *TICS &= ~TICS_ON_AXIS;
  2032.         *TICS |= TICS_ON_BORDER;
  2033.         ++c_token;
  2034.     }
  2035.     if (almost_equals(c_token, "mi$rror")) {
  2036.         *TICS |= TICS_MIRROR;
  2037.         ++c_token;
  2038.     } else if (almost_equals(c_token, "nomi$rror")) {
  2039.         *TICS &= ~TICS_MIRROR;
  2040.         ++c_token;
  2041.     }
  2042.     if (almost_equals(c_token, "ro$tate")) {
  2043.         *ROTATE = TRUE;
  2044.         ++c_token;
  2045.     } else if (almost_equals(c_token, "noro$tate")) {
  2046.         *ROTATE = FALSE;
  2047.         ++c_token;
  2048.     }
  2049.     if (almost_equals(c_token, "au$tofreq")) {    /* auto tic interval */
  2050.         ++c_token;
  2051.         if (tdef->type == TIC_USER) {
  2052.         free_marklist(tdef->def.user);
  2053.         tdef->def.user = NULL;
  2054.         }
  2055.         tdef->type = TIC_COMPUTED;
  2056.     }
  2057.     /* user spec. is last */ 
  2058.     else if (!END_OF_COMMAND) {
  2059.         load_tics(AXIS, tdef);
  2060.     }
  2061.     }
  2062.     if (almost_equals(c_token, nocmd)) {    /* NOSTRING */
  2063.     *TICS = NO_TICS;
  2064.     c_token++;
  2065.     match = 1;
  2066.     }
  2067. /* other options */
  2068.  
  2069.     (void) strcpy(sfxptr, "m$tics");    /* MONTH */
  2070.     if (almost_equals(c_token, cmdptr)) {
  2071.     if (tdef->type == TIC_USER) {
  2072.         free_marklist(tdef->def.user);
  2073.         tdef->def.user = NULL;
  2074.     }
  2075.     tdef->type = TIC_MONTH;
  2076.     ++c_token;
  2077.     match = 1;
  2078.     }
  2079.     if (almost_equals(c_token, nocmd)) {    /* NOMONTH */
  2080.     tdef->type = TIC_COMPUTED;
  2081.     ++c_token;
  2082.     match = 1;
  2083.     }
  2084.     (void) strcpy(sfxptr, "d$tics");    /* DAYS */
  2085.     if (almost_equals(c_token, cmdptr)) {
  2086.     match = 1;
  2087.     if (tdef->type == TIC_USER) {
  2088.         free_marklist(tdef->def.user);
  2089.         tdef->def.user = NULL;
  2090.     }
  2091.     tdef->type = TIC_DAY;
  2092.     ++c_token;
  2093.     }
  2094.     if (almost_equals(c_token, nocmd)) {    /* NODAYS */
  2095.     tdef->type = TIC_COMPUTED;
  2096.     ++c_token;
  2097.     match = 1;
  2098.     }
  2099.     *cmdptr = 'm';
  2100.     (void) strcpy(cmdptr + 1, tic_side);
  2101.     (void) strcat(cmdptr, "t$ics");    /* MINISTRING */
  2102.  
  2103.     if (almost_equals(c_token, cmdptr)) {
  2104.     struct value freq;
  2105.     c_token++;
  2106.     match = 1;
  2107.     if (END_OF_COMMAND) {
  2108.         *MTICS = MINI_AUTO;
  2109.     } else if (almost_equals(c_token, "def$ault")) {
  2110.         *MTICS = MINI_DEFAULT;
  2111.         ++c_token;
  2112.     } else {
  2113.         *FREQ = real(const_express(&freq));
  2114.         *FREQ = floor(*FREQ);
  2115.         *MTICS = MINI_USER;
  2116.     }
  2117.     }
  2118.     if (almost_equals(c_token, nocmd)) {    /* NOMINI */
  2119.     *MTICS = FALSE;
  2120.     c_token++;
  2121.     match = 1;
  2122.     }
  2123.     return (match);
  2124. }
  2125.  
  2126.  
  2127. /* process a 'set {x/y/z}label command */
  2128. /* set {x/y/z}label {label_text} {x}{,y} */
  2129. static void set_xyzlabel(label)
  2130. label_struct *label;
  2131. {
  2132.     c_token++;
  2133.     if (END_OF_COMMAND) {    /* no label specified */
  2134.     *label->text = '\0';
  2135.     return;
  2136.     }
  2137.     if (isstring(c_token)) {
  2138.     /* We have string specified - grab it. */
  2139.     quote_str(label->text, c_token, MAX_LINE_LEN);
  2140.     c_token++;
  2141.     }
  2142.     if (END_OF_COMMAND)
  2143.     return;
  2144.  
  2145.     if (!almost_equals(c_token, "font") && !isstring(c_token)) {
  2146.     /* We have x,y offsets specified */
  2147.     struct value a;
  2148.     if (!equals(c_token, ","))
  2149.         label->xoffset = real(const_express(&a));
  2150.  
  2151.     if (END_OF_COMMAND)
  2152.         return;
  2153.  
  2154.     if (equals(c_token, ",")) {
  2155.         c_token++;
  2156.         label->yoffset = real(const_express(&a));
  2157.     }
  2158.     }
  2159.     if (END_OF_COMMAND)
  2160.     return;
  2161.  
  2162.     /* optional keyword 'font' can go here */
  2163.  
  2164.     if (almost_equals(c_token, "f$ont"))
  2165.     ++c_token;        /* skip it */
  2166.  
  2167.     if (!isstring(c_token))
  2168.     int_error("Expected font", c_token);
  2169.  
  2170.     quote_str(label->font, c_token, MAX_LINE_LEN);
  2171.     c_token++;
  2172. }
  2173.  
  2174. /* process a 'set label' command */
  2175. /* set label {tag} {label_text} {at x,y} {pos} {font name,size} */
  2176. /* Entry font added by DJL */
  2177. static void set_label()
  2178. {
  2179.     struct value a;
  2180.     struct text_label *this_label = NULL;
  2181.     struct text_label *new_label = NULL;
  2182.     struct text_label *prev_label = NULL;
  2183.     struct position pos;
  2184.     char text[MAX_LINE_LEN + 1], font[MAX_LINE_LEN + 1];
  2185.     enum JUSTIFY just = LEFT;
  2186.     int rotate = 0;
  2187.     int tag;
  2188.     TBOOLEAN set_text, set_position, set_just = FALSE, set_rot = FALSE,
  2189.      set_font;
  2190.  
  2191.     /* get tag */
  2192.     if (!END_OF_COC_SERIESze = 1.0ing(c_token)
  2193.     && !equals(c_token, "at")
  2194.     && !equals(c_token, "left")
  2195.     && !equals(c_token, "center")
  2196.     && !equals(c_token, "centre")
  2197.     && !equals(c_token, "right")
  2198.     && !almost_equals(c_token, "rot$ate")
  2199.     && !almost_equals(c_token, "norot$ate")
  2200.     && !equals(c_token, "font")) {
  2201.     /* must be a tag expression! */
  2202.     tag = (int) real(const_express(&a));
  2203.     if (tag <= 0)
  2204.         int_error("tag must be > zero", c_token);
  2205.     } else
  2206.     tag = assign_label_tag();    /* default next tag */
  2207.  
  2208.     /* get text */
  2209.     if (!END_OF_COMMAND && isstring(c_token)) {
  2210.     /* get text */
  2211.     quote_str(text, c_token, MAX_LINE_LEN);
  2212.     c_token++;
  2213.     set_text = TRUE;
  2214.     } else {
  2215.     text[0] = '\0';        /* default no text */
  2216.     set_text = FALSE;
  2217.     }
  2218.  
  2219.     /* get justification - what the heck, let him put it here */
  2220.     if (!END_OF_COMMAND && !equals(c_token, "at") && !equals(c_token, "font")
  2221.     && !almost_equals(c_token, "rot$ate") && !almost_equals(c_token, "norot$ate")) {
  2222.     if (almost_equals(c_token, "l$eft")) {
  2223.         just = LEFT;
  2224.     } else if (almost_equals(c_token, "c$entre")
  2225.            || almost_equals(c_token, "c$enter")) {
  2226.         just = CENTRE;
  2227.     } else if (almost_equals(c_token, "r$ight")) {
  2228.         just = RIGHT;
  2229.     } else
  2230.         int_error("bad syntax in set label", c_token);
  2231.     c_token++;
  2232.     set_just = TRUE;
  2233.     }
  2234.     /* get position */
  2235.     if (!END_OF_COMMAND && equals(c_token, "at")) {
  2236.     c_token++;
  2237.  
  2238.     get_position(&pos);
  2239.     set_position = TRUE;
  2240.     } else {
  2241.     pos.x = pos.y = pos.z = 0;
  2242.     pos.scalex = pos.scaley = pos.scalez = first_axes;
  2243.     set_position = FALSE;
  2244.     }
  2245.  
  2246.     /* get justification */
  2247.     if (!END_OF_COMMAND && !almost_equals(c_token, "rot$ate") && !almost_equals(c_token, "norot$ate") && !equals(c_token, "font")) {
  2248.     if (set_just)
  2249.         int_error("only one justification is allowed", c_token);
  2250.     if (almost_equals(c_token, "l$eft")) {
  2251.         just = LEFT;
  2252.     } else if (almost_equals(c_token, "c$entre")
  2253.            || almost_equals(c_token, "c$enter")) {
  2254.         just = CENTRE;
  2255.     } else if (almost_equals(c_token, "r$ight")) {
  2256.         just = RIGHT;
  2257.     } else
  2258.         int_error("bad syntax in set label", c_token);
  2259.  
  2260.     c_token++;
  2261.     set_just = TRUE;
  2262.     }
  2263.     /* get rotation (added by RCC) */
  2264.     if (!END_OF_COMMAND && !equals(c_token, "font")) {
  2265.     if (almost_equals(c_token, "rot$ate")) {
  2266.         rotate = TRUE;
  2267.     } else if (almost_equals(c_token, "norot$ate")) {
  2268.         rotate = FALSE;
  2269.     } else
  2270.         int_error("bad syntax in set label", c_token);
  2271.  
  2272.     c_token++;
  2273.     set_rot = TRUE;
  2274.     }
  2275.     /* get font */
  2276.     font[0] = NUL;
  2277.     set_font = FALSE;
  2278.     if (!END_OF_COMMAND && equals(c_token, "font")) {
  2279.     c_token++;
  2280.     if (END_OF_COMMAND)
  2281.         int_error("font name and size expected", c_token);
  2282.     if (isstring(c_token)) {
  2283.         quote_str(font, c_token, MAX_ID_LEN);
  2284.         /* get 'name,size', no further check */
  2285.         set_font = TRUE;
  2286.     } else
  2287.         int_error("'fontname,fontsize' expected", c_token);
  2288.  
  2289.     c_token++;
  2290.     }                /* Entry font added by DJL */
  2291.     if (!END_OF_COMMAND)
  2292.     int_error("extraenous or out-of-order arguments in set label", c_token);
  2293.  
  2294.     /* OK! add label */
  2295.     if (first_label != NULL) {    /* skip to last label */
  2296.     for (this_label = first_label; this_label != NULL;
  2297.          prev_label = this_label, this_label = this_label->next)
  2298.         /* is this the label we want? */
  2299.         if (tag <= this_label->tag)
  2300.         break;
  2301.     }
  2302.     if (this_label != NULL && tag == this_label->tag) {
  2303.     /* changing the label */
  2304.     if (set_position) {
  2305.         this_label->place = pos;
  2306.     }
  2307.     if (set_text)
  2308.         (void) strcpy(this_label->text, text);
  2309.     if (set_just)
  2310.         this_label->pos = just;
  2311.     if (set_rot)
  2312.         this_label->rotate = rotate;
  2313.     if (set_font)
  2314.         (void) strcpy(this_label->font, font);
  2315.     } else {
  2316.     /* adding the label */
  2317.     new_label = (struct text_label *)
  2318.         gp_alloc((unsigned long) sizeof(struct text_label), "label");
  2319.     if (prev_label != NULL)
  2320.         prev_label->next = new_label;    /* add it to end of list */
  2321.     else
  2322.         first_label = new_label;    /* make it start of list */
  2323.     new_label->tag = tag;
  2324.     new_label->next = this_label;
  2325.     new_label->place = pos;
  2326.     (void) strcpy(new_label->text, text);
  2327.     new_label->pos = just;
  2328.     new_label->rotate = rotate;
  2329.     (void) strcpy(new_label->font, font);
  2330.     }
  2331. }                /* Entry font added by DJL */
  2332.  
  2333. /* process 'set nolabel' command */
  2334. /* set nolabel {tag} */
  2335. static void set_nolabel()
  2336. {
  2337.     struct value a;
  2338.     struct text_label *this_label;
  2339.     struct text_label *prev_label;
  2340.     int tag;
  2341.  
  2342.     if (END_OF_COMMAND) {
  2343.     /* delete all labels */
  2344.     while (first_label != NULL)
  2345.         delete_label((struct text_label *) NULL, first_label);
  2346.     } else {
  2347.     /* get tag */
  2348.     tag = (int) real(const_express(&a));
  2349.     if (!END_OF_COMMAND)
  2350.         int_error("extraneous arguments to set nolabel", c_token);
  2351.     for (this_label = first_label, prev_label = NULL;
  2352.          this_label != NULL;
  2353.          prev_label = this_label, this_label = this_label->next) {
  2354.         if (this_label->tag == tag) {
  2355.         delete_label(prev_label, this_label);
  2356.         return;        /* exit, our job is done */
  2357.         }
  2358.     }
  2359.     int_error("label not found", c_token);
  2360.     }
  2361. }
  2362.  
  2363. /* assign a new label tag */
  2364. /* labels are kept sorted by tag number, so this is easy */
  2365. static int /* the lowest unassigned tag number */ assign_label_tag()
  2366. {
  2367.     struct text_label *this_label;
  2368.     int last = 0;        /* previous tag value */
  2369.  
  2370.     for (this_label = first_label; this_label != NULL;
  2371.      this_label = this_label->next)
  2372.     if (this_label->tag == last + 1)
  2373.         last++;
  2374.     else
  2375.         break;
  2376.  
  2377.     return (last + 1);
  2378. }
  2379.  
  2380. /* delete label from linked list started by first_label.
  2381.  * called with pointers to the previous label (prev) and the 
  2382.  * label to delete (this).
  2383.  * If there is no previous label (the label to delete is
  2384.  * first_label) then call with prev = NULL.
  2385.  */
  2386. static void delete_label(prev, this)
  2387. struct text_label *prev, *this;
  2388. {
  2389.     if (this != NULL) {        /* there really is something to delete */
  2390.     if (prev != NULL)    /* there is a previous label */
  2391.         prev->next = this->next;
  2392.     else            /* this = first_label so change first_label */
  2393.         first_label = this->next;
  2394.     free((char *) this);
  2395.     }
  2396. }
  2397.  
  2398.  
  2399. /* process a 'set arrow' command */
  2400. /* set arrow {tag} {from x,y} {to x,y} {{no}head} */
  2401. static void set_arrow()
  2402. {
  2403.     struct value a;
  2404.     struct arrow_def *this_arrow = NULL;
  2405.     struct arrow_def *new_arrow = NULL;
  2406.     struct arrow_def *prev_arrow = NULL;
  2407.     struct position spos, epos;
  2408.     struct lp_style_type loc_lp;
  2409.     int axes = FIRST_AXES;
  2410.     int tag;
  2411.     TBOOLEAN set_start, set_end, head = 1, set_axes = 0, set_line = 0;
  2412.  
  2413.     /* Init struct lp_style_type loc_lp */
  2414.     reset_lp_properties (&loc_lp);
  2415.  
  2416.     /* get tag */
  2417.     if (!END_OF_COMMAND
  2418.     && !equals(c_token, "from")
  2419.     && !equals(c_token, "to")
  2420.     && !equals(c_token, "first")
  2421.     && !equals(c_token, "second")) {
  2422.     /* must be a tag expression! */
  2423.     tag = (int) real(const_express(&a));
  2424.     if (tag <= 0)
  2425.         int_error("tag must be > zero", c_token);
  2426.     } else
  2427.     tag = assign_arrow_tag();    /* default next tag */
  2428.  
  2429.     if (!END_OF_COMMAND && equals(c_token, "first")) {
  2430.     ++c_token;
  2431.     axes = FIRST_AXES;
  2432.     set_axes = 1;
  2433.     } else if (!END_OF_COMMAND && equals(c_token, "second")) {
  2434.     ++c_token;
  2435.     axes = SECOND_AXES;
  2436.     set_axes = 1;
  2437.     }
  2438.     /* get start position */
  2439.     if (!END_OF_COMMAND && equals(c_token, "from")) {
  2440.     c_token++;
  2441.     if (END_OF_COMMAND)
  2442.         int_error("start coordinates expected", c_token);
  2443.     /* get coordinates */
  2444.     get_position(&spos);
  2445.     set_start = TRUE;
  2446.     } else {
  2447.     spos.x = spos.y = spos.z = 0;
  2448.     spos.scalex = spos.scaley = spos.scalez = first_axes;
  2449.     set_start = FALSE;
  2450.     }
  2451.  
  2452.     /* get end position */
  2453.     if (!END_OF_COMMAND && equals(c_token, "to")) {
  2454.     c_token++;
  2455.     if (END_OF_COMMAND)
  2456.         int_error("end coordinates expected", c_token);
  2457.     /* get coordinates */
  2458.     get_position(&epos);
  2459.     set_end = TRUE;
  2460.     } else {
  2461.     epos.x = epos.y = epos.z = 0;
  2462.     epos.scalex = epos.scaley = epos.scalez = first_axes;
  2463.     set_end = FALSE;
  2464.     }
  2465.  
  2466.     /* get start position - what the heck, either order is ok */
  2467.     if (!END_OF_COMMAND && equals(c_token, "from")) {
  2468.     if (set_start)
  2469.         int_error("only one 'from' is allowed", c_token);
  2470.     c_token++;
  2471.     if (END_OF_COMMAND)
  2472.         int_error("start coordinates expected", c_token);
  2473.     /* get coordinates */
  2474.     get_position(&spos);
  2475.     set_start = TRUE;
  2476.     }
  2477.     if (!END_OF_COMMAND && equals(c_token, "nohead")) {
  2478.     c_token++;
  2479.     head = 0;
  2480.     }
  2481.     if (!END_OF_COMMAND && equals(c_token, "head")) {
  2482.     c_token++;
  2483.     head = 1;
  2484.     }
  2485.     set_line = 1;
  2486.  
  2487.     /* pick up a line spec - allow ls, but no point. */
  2488.     LP_PARSE(loc_lp, 1, 0, 0, 0);
  2489.     loc_lp.pointflag = 0;    /* standard value for arrows, don't use points */
  2490.  
  2491.     if (!END_OF_COMMAND)
  2492.     int_error("extraneous or out-of-order arguments in set arrow", c_token);
  2493.  
  2494.     /* OK! add arrow */
  2495.     if (first_arrow != NULL) {    /* skip to last arrow */
  2496.     for (this_arrow = first_arrow; this_arrow != NULL;
  2497.          prev_arrow = this_arrow, this_arrow = this_arrow->next)
  2498.         /* is this the arrow we want? */
  2499.         if (tag <= this_arrow->tag)
  2500.         break;
  2501.     }
  2502.     if (this_arrow != NULL && tag == this_arrow->tag) {
  2503.     /* changing the arrow */
  2504.     if (set_start) {
  2505.         this_arrow->start = spos;
  2506.     }
  2507.     if (set_end) {
  2508.         this_arrow->end = epos;
  2509.     }
  2510.     this_arrow->head = head;
  2511.     if (set_line) {
  2512.         this_arrow->lp_properties = loc_lp;
  2513.     }
  2514.     } else {
  2515.     /* adding the arrow */
  2516.     new_arrow = (struct arrow_def *)
  2517.         gp_alloc((unsigned long) sizeof(struct arrow_def), "arrow");
  2518.     if (prev_arrow != NULL)
  2519.         prev_arrow->next = new_arrow;    /* add it to end of list */
  2520.     else
  2521.         first_arrow = new_arrow;    /* make it start of list */
  2522.     new_arrow->tag = tag;
  2523.     new_arrow->next = this_arrow;
  2524.     new_arrow->start = spos;
  2525.     new_arrow->end = epos;
  2526.     new_arrow->head = head;
  2527.     new_arrow->lp_properties = loc_lp;
  2528.     }
  2529. }
  2530.  
  2531. /* process 'set noarrow' command */
  2532. /* set noarrow {tag} */
  2533. static void set_noarrow()
  2534. {
  2535.     struct value a;
  2536.     struct arrow_def *this_arrow;
  2537.     struct arrow_def *prev_arrow;
  2538.     int tag;
  2539.  
  2540.     if (END_OF_COMMAND) {
  2541.     /* delete all arrows */
  2542.     while (first_arrow != NULL)
  2543.         delete_arrow((struct arrow_def *) NULL, first_arrow);
  2544.     } else {
  2545.     /* get tag */
  2546.     tag = (int) real(const_express(&a));
  2547.     if (!END_OF_COMMAND)
  2548.         int_error("extraneous arguments to set noarrow", c_token);
  2549.     for (this_arrow = first_arrow, prev_arrow = NULL;
  2550.          this_arrow != NULL;
  2551.          prev_arrow = this_arrow, this_arrow = this_arrow->next) {
  2552.         if (this_arrow->tag == tag) {
  2553.         delete_arrow(prev_arrow, this_arrow);
  2554.         return;        /* exit, our job is done */
  2555.         }
  2556.     }
  2557.     int_error("arrow not found", c_token);
  2558.     }
  2559. }
  2560.  
  2561. /* assign a new arrow tag */
  2562. /* arrows are kept sorted by tag number, so this is easy */
  2563. static int /* the lowest unassigned tag number */ assign_arrow_tag()
  2564. {
  2565.     struct arrow_def *this_arrow;
  2566.     int last = 0;        /* previous tag value */
  2567.  
  2568.     for (this_arrow = first_arrow; this_arrow != NULL;
  2569.      this_arrow = this_arrow->next)
  2570.     if (this_arrow->tag == last + 1)
  2571.         last++;
  2572.     else
  2573.         break;
  2574.  
  2575.     return (last + 1);
  2576. }
  2577.  
  2578. /* delete arrow from linked list started by first_arrow.
  2579.  * called with pointers to the previous arrow (prev) and the 
  2580.  * arrow to delete (this).
  2581.  * If there is no previous arrow (the arrow to delete is
  2582.  * first_arrow) then call with prev = NULL.
  2583.  */
  2584. static void delete_arrow(prev, this)
  2585. struct arrow_def *prev, *this;
  2586. {
  2587.     if (this != NULL) {        /* there really is something to delete */
  2588.     if (prev != NULL)    /* there is a previous arrow */
  2589.         prev->next = this->next;
  2590.     else            /* this = first_arrow so change first_arrow */
  2591.         first_arrow = this->next;
  2592.     free((char *) this);
  2593.     }
  2594. }
  2595.  
  2596. /* ======================================================== */
  2597. /* process a 'set linestyle' command */
  2598. /* set linestyle {tag} {linetype n} {linewidth x} {pointtype n} {pointsize x} */
  2599. static void set_linestyle()
  2600. {
  2601.     struct value a;
  2602.     struct linestyle_def *this_linestyle = NULL;
  2603.     struct linestyle_def *new_linestyle = NULL;
  2604.     struct linestyle_def *prev_linestyle = NULL;
  2605.     struct lp_style_type loc_lp;
  2606.     int tag;
  2607.  
  2608.     /* Init struct lp_style_type loc_lp */
  2609.     reset_lp_properties (&loc_lp);
  2610.  
  2611.     /* get tag */
  2612.     if (!END_OF_COMMAND) {
  2613.     /* must be a tag expression! */
  2614.     tag = (int) real(const_express(&a));
  2615.     if (tag <= 0)
  2616.         int_error("tag must be > zero", c_token);
  2617.     } else
  2618.     tag = assign_linestyle_tag();    /* default next tag */
  2619.  
  2620.     /* pick up a line spec : dont allow ls, do allow point type
  2621.      * default to same line type = point type = tag
  2622.      */
  2623.     LP_PARSE(loc_lp, 0, 1, tag - 1, tag - 1);
  2624.  
  2625.     if (!END_OF_COMMAND)
  2626.     int_error("extraneous or out-of-order arguments in set linestyle", c_token);
  2627.  
  2628.     /* OK! add linestyle */
  2629.     if (first_linestyle != NULL) {    /* skip to last linestyle */
  2630.     for (this_linestyle = first_linestyle; this_linestyle != NULL;
  2631.          prev_linestyle = this_linestyle, this_linestyle = this_linestyle->next)
  2632.         /* is this the linestyle we want? */
  2633.         if (tag <= this_linestyle->tag)
  2634.         break;
  2635.     }
  2636.     if (this_linestyle != NULL && tag == this_linestyle->tag) {
  2637.     /* changing the linestyle */
  2638.     this_linestyle->lp_properties = loc_lp;
  2639.     } else {
  2640.     /* adding the linestyle */
  2641.     new_linestyle = (struct linestyle_def *)
  2642.         gp_alloc((unsigned long) sizeof(struct linestyle_def), "linestyle");
  2643.     if (prev_linestyle != NULL)
  2644.         prev_linestyle->next = new_linestyle;    /* add it to end of list */
  2645.     else
  2646.         first_linestyle = new_linestyle;    /* make it start of list */
  2647.     new_linestyle->tag = tag;
  2648.     new_linestyle->next = this_linestyle;
  2649.     new_linestyle->lp_properties = loc_lp;
  2650.     }
  2651. }
  2652.  
  2653. /* process 'set nolinestyle' command */
  2654. /* set nolinestyle {tag} */
  2655. static void set_nolinestyle()
  2656. {
  2657.     struct value a;
  2658.     struct linestyle_def *this, *prev;
  2659.     int tag;
  2660.  
  2661.     if (END_OF_COMMAND) {
  2662.     /* delete all linestyles */
  2663.     while (first_linestyle != NULL)
  2664.         delete_linestyle((struct linestyle_def *) NULL, first_linestyle);
  2665.     } else {
  2666.     /* get tag */
  2667.     tag = (int) real(const_express(&a));
  2668.     if (!END_OF_COMMAND)
  2669.         int_error("extraneous arguments to set nolinestyle", c_token);
  2670.     for (this = first_linestyle, prev = NULL;
  2671.          this != NULL;
  2672.          prev = this, this = this->next) {
  2673.         if (this->tag == tag) {
  2674.         delete_linestyle(prev, this);
  2675.         return;        /* exit, our job is done */
  2676.         }
  2677.     }
  2678.     int_error("linestyle not found", c_token);
  2679.     }
  2680. }
  2681.  
  2682. /* assign a new linestyle tag */
  2683. /* linestyles are kept sorted by tag number, so this is easy */
  2684. static int /* the lowest unassigned tag number */ assign_linestyle_tag()
  2685. {
  2686.     struct linestyle_def *this;
  2687.     int last = 0;        /* previous tag value */
  2688.  
  2689.     for (this = first_linestyle; this != NULL; this = this->next)
  2690.     if (this->tag == last + 1)
  2691.         last++;
  2692.     else
  2693.         break;
  2694.  
  2695.     return (last + 1);
  2696. }
  2697.  
  2698. /* delete linestyle from linked list started by first_linestyle.
  2699.  * called with pointers to the previous linestyle (prev) and the 
  2700.  * linestyle to delete (this).
  2701.  * If there is no previous linestyle (the linestyle to delete is
  2702.  * first_linestyle) then call with prev = NULL.
  2703.  */
  2704. static void delete_linestyle(prev, this)
  2705. struct linestyle_def *prev, *this;
  2706. {
  2707.     if (this != NULL) {        /* there really is something to delete */
  2708.     if (prev != NULL)    /* there is a previous linestyle */
  2709.         prev->next = this->next;
  2710.     else            /* this = first_linestyle so change first_linestyle */
  2711.         first_linestyle = this->next;
  2712.     free((char *) this);
  2713.     }
  2714. }
  2715.  
  2716. /*
  2717.  * auxiliary functions for the `set linestyle` command
  2718.  */
  2719.  
  2720. void lp_use_properties(lp, tag, pointflag)
  2721. struct lp_style_type *lp;
  2722. int tag, pointflag;
  2723. {
  2724.     /*  This function looks for a linestyle defined by 'tag' and copies
  2725.      *  its data into the structure 'lp'.
  2726.      *
  2727.      *  If 'pointflag' equals ZERO, the properties belong to a linestyle
  2728.      *  used with arrows.  In this case no point properties will be
  2729.      *  passed to the terminal (cf. function 'term_apply_lp_properties' below).
  2730.      */
  2731.  
  2732.     struct linestyle_def *this;
  2733.  
  2734.     this = first_linestyle;
  2735.     while (this != NULL) {
  2736.     if (this->tag == tag) {
  2737.         *lp = this->lp_properties;
  2738.         lp->pointflag = pointflag;
  2739.         return;
  2740.     } else {
  2741.         this = this->next;
  2742.     }
  2743.     }
  2744.  
  2745.     /* tag not found: */
  2746.     int_error("linestyle not found", NO_CARET);
  2747. }
  2748.  
  2749. /* ======================================================== */
  2750.  
  2751. enum PLOT_STYLE /* not static; used by command.c */ get_style()
  2752. {
  2753.     register enum PLOT_STYLE ps = LINES;    /* HBB: initial value, for 'gcc -W} */
  2754.  
  2755.     c_token++;
  2756.     if (almost_equals(c_token, "l$ines"))
  2757.     ps = LINES;
  2758.     else if (almost_equals(c_token, "i$mpulses"))
  2759.     ps = IMPULSES;
  2760.     else if (almost_equals(c_token, "p$oints"))
  2761.     ps = POINTSTYLE;
  2762.     else if (almost_equals(c_token, "linesp$oints") || equals(c_token, "lp"))
  2763.     ps = LINESPOINTS;
  2764.     else if (almost_equals(c_token, "d$ots"))
  2765.     ps = DOTS;
  2766.     else if (almost_equals(c_token, "ye$rrorbars"))
  2767.     ps = YERRORBARS;
  2768.     else if (almost_equals(c_token, "e$rrorbars"))
  2769.     ps = YERRORBARS;
  2770.     else if (almost_equals(c_token, "xe$rrorbars"))
  2771.     ps = XERRORBARS;
  2772.     else if (almost_equals(c_token, "xye$rrorbars"))
  2773.     ps = XYERRORBARS;
  2774.     else if (almost_equals(c_token, "boxes"))
  2775.     ps = BOXES;
  2776.     else if (almost_equals(c_token, "boxer$rorbars"))
  2777.     ps = BOXERROR;
  2778.     else if (almost_equals(c_token, "boxx$yerrorbars"))
  2779.     ps = BOXXYERROR;
  2780.     else if (almost_equals(c_token, "st$eps"))
  2781.     ps = STEPS;
  2782.     else if (almost_equals(c_token, "fs$teps"))
  2783.     ps = FSTEPS;
  2784.     else if (almost_equals(c_token, "his$teps"))
  2785.     ps = HISTEPS;
  2786.     else if (almost_equals(c_token, "vec$tor"))        /* HBB: minor cosmetic change */
  2787.     ps = VECTOR;
  2788.     else if (almost_equals(c_token, "fin$ancebars"))
  2789.     ps = FINANCEBARS;
  2790.     else if (almost_equals(c_token, "can$dlesticks"))
  2791.     ps = CANDLESTICKS;
  2792.     else {
  2793.     int_error("expecting 'lines', 'points', 'linespoints', 'dots', 'impulses',\n\
  2794.         'yerrorbars', 'xerrorbars', 'xyerrorbars', 'steps', 'fsteps', 'histeps',\n\
  2795.         'boxes', 'boxerrorbars', 'boxxyerrorbars', 'vector', 'financebars', 'candlesticks'", c_token);
  2796.     return LINES;        /* keep gcc -Wuninitialised happy */
  2797.     }
  2798.     c_token++;
  2799.     return (ps);
  2800. }
  2801.  
  2802. /* For set [xy]tics... command */
  2803. static void load_tics(axis, tdef)
  2804. int axis;
  2805. struct ticdef *tdef;        /* change this ticdef */
  2806. {
  2807.     if (equals(c_token, "(")) {    /* set : TIC_USER */
  2808.     c_token++;
  2809.     load_tic_user(axis, tdef);
  2810.     } else {            /* series : TIC_SERIES */
  2811.     load_tic_series(axis, tdef);
  2812.     }
  2813. }
  2814.  
  2815. /* load TIC_USER definition */
  2816. /* (tic[,tic]...)
  2817.  * where tic is ["string"] value
  2818.  * Left paren is already scanned off before entry.
  2819.  */
  2820. static void load_tic_user(axis, tdef)
  2821. int axis;
  2822. struct ticdef *tdef;
  2823. {
  2824.     struct ticmark *list = NULL;    /* start of list */
  2825.     struct ticmark *last = NULL;    /* end of list */
  2826.     struct ticmark *tic = NULL;    /* new ticmark */
  2827.     char temp_string[MAX_LINE_LEN];
  2828.  
  2829.     while (!END_OF_COMMAND) {
  2830.     /* parse a new ticmark */
  2831.     tic = (struct ticmark *) gp_alloc((unsigned long) sizeof(struct ticmark), (char *) NULL);
  2832.     if (tic == (struct ticmark *) NULL) {
  2833.         free_marklist(list);
  2834.         int_error("out of memory for tic mark", c_token);
  2835.     }
  2836.     /* syntax is  (  ['format'] value , ... )
  2837.      * but for timedata, the value itself is a string, which
  2838.      * complicates things somewhat
  2839.      */
  2840.  
  2841.     /* has a string with it? */
  2842.     if (isstring(c_token) &&
  2843.         (datatype[axis] != TIME || isstring(c_token + 1))) {
  2844.         quote_str(temp_string, c_token, MAX_LINE_LEN);
  2845.         tic->label = gp_alloc((unsigned long) strlen(temp_string) + 1, "tic label");
  2846.         (void) strcpy(tic->label, temp_string);
  2847.         c_token++;
  2848.     } else
  2849.         tic->label = NULL;
  2850.  
  2851.     /* in any case get the value */
  2852.     GET_NUM_OR_TIME(tic->position, axis);
  2853.     tic->next = NULL;
  2854.  
  2855.     /* append to list */
  2856.     if (list == NULL)
  2857.         last = list = tic;    /* new list */
  2858.     else {            /* append to list */
  2859.         last->next = tic;
  2860.         last = tic;
  2861.     }
  2862.  
  2863.     /* expect "," or ")" here */
  2864.     if (!END_OF_COMMAND && equals(c_token, ","))
  2865.         c_token++;        /* loop again */
  2866.     else
  2867.         break;        /* hopefully ")" */
  2868.     }
  2869.  
  2870.     if (END_OF_COMMAND || !equals(c_token, ")")) {
  2871.     free_marklist(list);
  2872.     int_error("expecting right parenthesis )", c_token);
  2873.     }
  2874.     c_token++;
  2875.  
  2876.     /* successful list */
  2877.     if (tdef->type == TIC_USER) {
  2878.     /* remove old list */
  2879.     /* VAX Optimiser was stuffing up following line. Turn Optimiser OFF */
  2880.     free_marklist(tdef->def.user);
  2881.     tdef->def.user = NULL;
  2882.     }
  2883.     tdef->type = TIC_USER;
  2884.     tdef->def.user = list;
  2885. }
  2886.  
  2887. static void free_marklist(list)
  2888. struct ticmark *list;
  2889. {
  2890.     register struct ticmark *freeable;
  2891.  
  2892.     while (list != NULL) {
  2893.     freeable = list;
  2894.     list = list->next;
  2895.     if (freeable->label != NULL)
  2896.         free((char *) freeable->label);
  2897.     free((char *) freeable);
  2898.     }
  2899. }
  2900.  
  2901. /* load TIC_SERIES definition */
  2902. /* [start,]incr[,end] */
  2903. static void load_tic_series(axis, tdef)
  2904. int axis;
  2905. struct ticdef *tdef;
  2906. {
  2907.     double start, incr, end;
  2908.     int incr_token;
  2909.  
  2910.     GET_NUM_OR_TIME(start, axis);
  2911.  
  2912.     if (!equals(c_token, ",")) {
  2913.     /* only step specified */
  2914.     incr = start;
  2915.     start = -VERYLARGE;
  2916.     end = VERYLARGE;
  2917.     } else {
  2918.  
  2919.     c_token++;
  2920.  
  2921.     incr_token = c_token;
  2922.     GET_NUM_OR_TIME(incr, axis);
  2923.  
  2924.     if (END_OF_COMMAND)
  2925.         end = VERYLARGE;
  2926.     else {
  2927.         if (!equals(c_token, ","))
  2928.         int_error("expecting comma to separate incr,end", c_token);
  2929.         c_token++;
  2930.         GET_NUM_OR_TIME(end, axis);
  2931.     }
  2932.     if (!END_OF_COMMAND)
  2933.         int_error("tic series is defined by [start,]increment[,end]", c_token);
  2934.  
  2935.     if (start < end && incr <= 0)
  2936.         int_error("increment must be positive", incr_token);
  2937.     if (start > end && incr >= 0)
  2938.         int_error("increment must be negative", incr_token);
  2939.     if (start > end) {
  2940.         /* put in order */
  2941.         double numtics;
  2942.         numtics = floor((end * (1 + SIGNIF) - start) / incr);
  2943.         end = start;
  2944.         start = end + numtics * incr;
  2945.         incr = -incr;
  2946. /*
  2947.    double temp = start;
  2948.    start = end;
  2949.    end = temp;
  2950.    incr = -incr;
  2951.  */
  2952.     }
  2953.     }
  2954.  
  2955.     if (tdef->type == TIC_USER) {
  2956.     /* remove old list */
  2957.     /* VAX Optimiser was stuffing up following line. Turn Optimiser OFF */
  2958.     free_marklist(tdef->def.user);
  2959.     tdef->def.user = NULL;
  2960.     }
  2961.     tdef->type = TIC_SERIES;
  2962.     tdef->def.series.start = start;
  2963.     tdef->def.series.incr = incr;
  2964.     tdef->def.series.end = end;
  2965. }
  2966.  
  2967. static void load_offsets(a, b, c, d)
  2968. double *a, *b, *c, *d;
  2969. {
  2970.     struct value t;
  2971.  
  2972.     *a = real(const_express(&t));    /* loff value */
  2973.     if (!equals(c_token, ","))
  2974.     return;
  2975.  
  2976.     c_token++;
  2977.     *b = real(const_express(&t));    /* roff value */
  2978.     if (!equals(c_token, ","))
  2979.     return;
  2980.  
  2981.     c_token++;
  2982.     *c = real(const_express(&t));    /* toff value */
  2983.     if (!equals(c_token, ","))
  2984.     return;
  2985.  
  2986.     c_token++;
  2987.     *d = real(const_express(&t));    /* boff value */
  2988. }
  2989.  
  2990. TBOOLEAN            /* new value for autosc */
  2991. load_range(axis, a, b, autosc)        /* also used by command.c */
  2992. int axis;
  2993. double *a, *b;
  2994. TBOOLEAN autosc;
  2995. {
  2996.     if (equals(c_token, "]"))
  2997.     return (autosc);
  2998.     if (END_OF_COMMAND) {
  2999.     int_error("starting range value or ':' or 'to' expected", c_token);
  3000.     } else if (!equals(c_token, "to") && !equals(c_token, ":")) {
  3001.     if (equals(c_token, "*")) {
  3002.         autosc |= 1;
  3003.         c_token++;
  3004.     } else {
  3005.         GET_NUM_OR_TIME(*a, axis);
  3006.         autosc &= 2;
  3007.     }
  3008.     }
  3009.     if (!equals(c_token, "to") && !equals(c_token, ":"))
  3010.     int_error("':' or keyword 'to' expected", c_token);
  3011.     c_token++;
  3012.     if (!equals(c_token, "]")) {
  3013.     if (equals(c_token, "*")) {
  3014.         autosc |= 2;
  3015.         c_token++;
  3016.     } else {
  3017.         GET_NUM_OR_TIME(*b, axis);
  3018.         autosc &= 1;
  3019.     }
  3020.     }
  3021.     return (autosc);
  3022. }
  3023.  
  3024. /* return 1 if format looks like a numeric format
  3025.  * ie more than one %{efg}, or %something-else
  3026.  */
  3027.  
  3028. static int looks_like_numeric(format)
  3029. char *format;
  3030. {
  3031.     if (!(format = strchr(format, '%')))
  3032.     return 0;
  3033.  
  3034.     while (++format, (*format >= '0' && *format <= '9') || *format == '.');
  3035.  
  3036.     return (*format == 'f' || *format == 'g' || *format == 'e');
  3037. }
  3038.  
  3039.  
  3040. /* parse a position of the form
  3041.  *    [coords] x, [coords] y {,[coords] z}
  3042.  * where coords is one of first,second.graph,screen
  3043.  * if first or second, we need to take datatype into account
  3044.  * mixed co-ordinates are for specialists, but it's not particularly
  3045.  * hard to implement...
  3046.  */
  3047.  
  3048. #define GET_NUMBER_OR_TIME(store,axes,axis) \
  3049. do{if (axes >= 0 && datatype[axes+axis] == TIME && isstring(c_token) ) { \
  3050.     char ss[80]; struct tm tm; \
  3051.     quote_str(ss,c_token, 80); ++c_token; \
  3052.     if (gstrptime(ss,timefmt,&tm)) store = (double) gtimegm(&tm); \
  3053.    } else {\
  3054.     struct value value; \
  3055.     store = real(const_express(&value));\
  3056.   }}while(0)
  3057.  
  3058.  
  3059. /* get_position_type - for use by get_position().
  3060.  * parses first/second/graph/screen keyword
  3061.  */
  3062.  
  3063. static void get_position_type(type, axes)
  3064. enum position_type *type;
  3065. int *axes;
  3066. {
  3067.     if (almost_equals(c_token, "fir$st")) {
  3068.     ++c_token;
  3069.     *type = first_axes;
  3070.     } else if (almost_equals(c_token, "sec$ond")) {
  3071.     ++c_token;
  3072.     *type = second_axes;
  3073.     } else if (almost_equals(c_token, "gr$aph")) {
  3074.     ++c_token;
  3075.     *type = graph;
  3076.     } else if (almost_equals(c_token, "sc$reen")) {
  3077.     ++c_token;
  3078.     *type = screen;
  3079.     }
  3080.     switch (*type) {
  3081.     case first_axes:
  3082.     *axes = FIRST_AXES;
  3083.     return;
  3084.     case second_axes:
  3085.     *axes = SECOND_AXES;
  3086.     return;
  3087.     default:
  3088.     *axes = (-1);
  3089.     return;
  3090.     }
  3091. }
  3092.  
  3093. /* get_position() - reads a position for label,arrow,key,... */
  3094.  
  3095. static void get_position(pos)
  3096. struct position *pos;
  3097. {
  3098.     int axes;
  3099.     enum position_type type = first_axes;
  3100.  
  3101.     get_position_type(&type, &axes);
  3102.     pos->scalex = type;
  3103.     GET_NUMBER_OR_TIME(pos->x, axes, FIRST_X_AXIS);
  3104.     if (!equals(c_token, ","))
  3105.     int_error("Expected comma", c_token);
  3106.     ++c_token;
  3107.     get_position_type(&type, &axes);
  3108.     pos->scaley = type;
  3109.     GET_NUMBER_OR_TIME(pos->y, axes, FIRST_Y_AXIS);
  3110.  
  3111.     /* z is not really allowed for a screen co-ordinate, but keep it simple ! */
  3112.     if (equals(c_token, ",")) {
  3113.     ++c_token;
  3114.     get_position_type(&type, &axes);
  3115.     pos->scalez = type;
  3116.     GET_NUMBER_OR_TIME(pos->z, axes, FIRST_Z_AXIS);
  3117.     } else {
  3118.     pos->z = 0;
  3119.     pos->scalez = type;    /* same as y */
  3120.     }
  3121. }
  3122.  
  3123. static void set_lp_properties(arg, allow_points, lt, pt, lw, ps)
  3124. struct lp_style_type *arg;
  3125. int allow_points, lt, pt;
  3126. double lw, ps;
  3127. {
  3128.     arg->pointflag = allow_points;
  3129.     arg->l_type = lt;
  3130.     arg->p_type = pt;
  3131.     arg->l_width = lw;
  3132.     arg->p_size = ps;
  3133. }
  3134.  
  3135. static void reset_lp_properties(arg)
  3136. struct lp_style_type *arg;
  3137. {
  3138.     /* See plot.h for struct lp_style_type */
  3139.     arg->pointflag = arg->l_type = arg->p_type = 0;
  3140.     arg->l_width = arg->p_size = 1.0;
  3141. }
  3142.  
  3143. static void set_locale(lcl)
  3144. char *lcl;
  3145. {
  3146. #ifndef NO_LOCALE_H
  3147.     int i;
  3148.     struct tm tm;
  3149.  
  3150.     if (setlocale(LC_TIME, lcl))
  3151.     safe_strncpy(cur_locale, lcl, sizeof(cur_locale));
  3152.     else
  3153.     int_error("Locale not available", c_token);
  3154.  
  3155.     /* we can do a *lot* better than this ; eg use system functions
  3156.      * where available; create values on first use, etc
  3157.      */
  3158.     memset(&tm, 0, sizeof(struct tm));
  3159.     for (i = 0; i < 7; ++i) {
  3160.     tm.tm_wday = i;        /* hope this enough */
  3161.     strftime(full_day_names[i], sizeof(full_day_names[i]), "%A", &tm);
  3162.     strftime(abbrev_day_names[i], sizeof(abbrev_day_names[i]), "%a", &tm);
  3163.     }
  3164.     for (i = 0; i < 12; ++i) {
  3165.     tm.tm_mon = i;        /* hope this enough */
  3166.     strftime(full_month_names[i], sizeof(full_month_names[i]), "%B", &tm);
  3167.     strftime(abbrev_month_names[i], sizeof(abbrev_month_names[i]), "%b", &tm);
  3168.     }
  3169. #else
  3170.     safe_strncpy(cur_locale, lcl, sizeof(cur_locale));
  3171. #endif /* NO_LOCALE_H */
  3172. }
  3173.